Laravel控制器中Request追加的user_id丢失,create方法报错求原因
这个问题的核心原因是:你直接给$request对象赋值属性的方式,并没有修改Laravel Request类底层存储的请求输入数据。
具体解释
Laravel的FormRequest(也就是你的ContactRequest)继承自Illuminate\Http\Request,这个类的请求输入数据是存储在内部的$input属性里的,而$request->all()方法返回的是这个内部存储的输入数组,并非对象的所有公共属性。
当你执行$request->user_id = $request->user()->id;时,只是给$request这个PHP对象添加了一个临时的公共属性,但这个属性并没有被加入到Request类管理的输入数据集里。所以当你调用$request->all()时,返回的依然是客户端提交的原始数据,自然看不到user_id字段——这也和你日志里输出的内容一致,日志打印的是Request的原始输入数组,不是对象的所有属性。
正确的解决方法
你有几种更合适的方式来实现需求:
方法1:使用Request的merge()方法合并输入
merge()方法会把你传入的数组合并到Request的输入数据集中,这样$request->all()就能包含user_id了:
public function store(ContactRequest $request) { // 合并user_id到请求输入中 $request->merge(['user_id' => $request->user()->id]); Log::debug($request->all()); // 现在能看到user_id了 Contact::create($request->all()); }
方法2:在create时手动组合数据
如果不想修改Request的输入,可以直接把请求数据和user_id组合成新数组传入create():
public function store(ContactRequest $request) { Contact::create(array_merge( $request->validated(), // 推荐用validated()而不是all(),只取验证通过的字段 ['user_id' => $request->user()->id] )); }
这里推荐使用
$request->validated()代替all(),因为它只会返回通过了ContactRequest验证规则的字段,更安全。
方法3:你的第二种写法(直接给模型赋值)
你已经在用的手动给模型属性赋值再save()的方式是完全没问题的,因为这种方式绕开了Request的输入,直接操作模型实例,自然不受Request输入的限制。
补充说明
Laravel的Request类提供了专门的方法来修改输入数据,比如merge()、replace(),这些方法才会真正更新内部的$input存储。直接给对象赋值属性只是PHP对象的常规操作,和Laravel的Request输入管理无关,所以不会影响all()、input()等方法的返回结果。
内容的提问来源于stack exchange,提问作者Iw Yu

