Rails 7中关联构建Foo时user_id为空,是否属于Bug?
Rails关联自动填充外键问题解答
模型关联定义
# user.rb has_one :company has_many :foos # company.rb belongs_to :user has_many :foos # foo.rb belongs_to :user belongs_to :company
执行代码User.first.company.foos.build后,返回结果为id: nil, user_id: nil, company_id: 1, ...,其中user_id为空。
疑问解答
1. 为何user_id会为空?
Rails的关联自动填充逻辑仅处理当前触发关联的直接外键。当你从Company实例的foos关联调用build时,Rails只会识别到当前关联是Company -> Foo,因此自动填充company_id。而user_id属于User -> Foo的关联外键,Rails不会主动遍历company.user这条关联链去自动填充该字段,它没有向上溯源的默认逻辑。
2. 是否必须通过.tap或.merge手动传入user_id?
不需要,有更贴合Rails风格的方案:
方案一:从User的关联出发创建Foo
直接通过User实例的foos关联创建,Rails会自动填充user_id,同时指定关联的company即可:user = User.first user.foos.build(company: user.company)这样生成的Foo对象会自动带上
user_id和company_id。方案二:给Foo模型添加回调
在Foo模型中添加before_validation回调,当关联了company时自动同步user_id:# foo.rb belongs_to :user belongs_to :company before_validation :sync_user_id_from_company private def sync_user_id_from_company self.user_id ||= company&.user_id if company.present? end之后再调用
User.first.company.foos.build时,会自动填充user_id。方案三:重写Company的foos关联方法
在Company模型中自定义foos关联的build方法,自动注入user_id:# company.rb has_many :foos do def build(attributes = {}) super(attributes.merge(user_id: proxy_association.owner.user_id)) end end这样调用
company.foos.build时,会自动带上当前company所属的user_id。
内容的提问来源于stack exchange,提问作者Sylar
相关产品推荐
相关产品推荐

