Rails中created_by无法赋值current_user,数据库存为nil问题
从你的描述来看,明明在调用@illustrator.save前已经把created_by设为current_user.id,但数据库里最终却是nil,这种情况大概率和模型回调、数据库字段定义、current_user的实现或者强参数配置有关,我帮你逐一排查:
1. 先检查Illustrator模型的回调逻辑
你没贴出Illustrator模型的代码,但如果模型里写了before_save、before_create这类回调,很可能在保存前把created_by给重置了。比如这种情况:
class Illustrator < ApplicationRecord before_save :clear_created_by private def clear_created_by self.created_by = nil # 这里会覆盖你之前设置的值 end end
如果有类似代码,要么修改回调的触发条件,要么直接删掉不必要的重置逻辑。
2. 确认数据库字段的定义是否正确
找到创建Illustrator表的迁移文件,检查created_by字段:
- 类型是不是
integer?毕竟current_user.id是整数,要是字段设成string类型,可能会导致隐性赋值失败 - 字段是否存在?要是迁移里没加这个字段,保存时不会报错但也存不进值
正确的迁移写法应该是这样:
class CreateIllustrators < ActiveRecord::Migration[7.0] def change create_table :illustrators do |t| t.string :name # 其他字段... t.integer :created_by # 类型为integer,默认允许null t.timestamps end end end
要是字段类型不对,就生成新迁移修改它。
3. 别让自定义的current_user干扰Devise的默认实现
Devise已经自带了current_user方法和对应的赋值逻辑,但你在ApplicationController里重写了current_user=:
private def current_user=(user) @current_user = user end
这可能会打乱Devise原本的用户状态维护逻辑。另外User模型里的cattr_accessor :current_user是类级别的属性,和Devise提供的请求级current_user完全不是一回事,很容易造成混淆。
建议把这两处自定义的current_user相关代码删掉,直接用Devise自带的current_user就好——毕竟你说保存前检查值是对的,但保不准回调或保存过程中因为这个自定义逻辑出问题。
4. 用日志输出确认值的变化
你可以在create动作里加几行打印代码,看看保存前后的值到底发生了什么:
def create @illustrator = Illustrator.new(illustrator_params) @illustrator.created_by = current_user.id # 控制台输出保存前的属性 puts "保存前created_by的值: #{@illustrator.created_by}" puts "Illustrator所有属性: #{@illustrator.attributes.inspect}" if @illustrator.save # 保存后直接从数据库查,确认最终值 saved_illustrator = Illustrator.find(@illustrator.id) puts "数据库里的created_by值: #{saved_illustrator.created_by}" redirect_to illustrator_path(@illustrator), notice: 'O autor foi criado com sucesso.' else render :new end end
通过控制台的输出,你能清楚看到值在哪个环节被清空了。
5. 可选优化:用关联代替直接赋值id
如果Illustrator和User模型加个关联,代码会更清晰,还能避免类型不匹配的问题:
# 在Illustrator模型里添加关联 class Illustrator < ApplicationRecord belongs_to :created_by_user, class_name: 'User', foreign_key: 'created_by', optional: true end # 然后在create动作里直接赋值对象 @illustrator.created_by_user = current_user
这种方式更符合Rails的关联设计,也能减少手动处理id的麻烦。
按照上面的步骤一步步排查,应该能找到问题所在。
内容的提问来源于stack exchange,提问作者Morgana Borges

