Rails中FactoryBot用build创建Transaction传入Item时item_id为空致校验失败
问题根因
- Rails 关联外键同步规则:对于
belongs_to关联,只有当被关联的对象拥有非nil的id时,赋值关联后才会自动同步外键字段(即这里的item_id)。如果被关联对象的id为nil,外键会保持空值。 - 直接
build(:transaction)正常的原因:你的 Transaction 工厂定义了item { build_stubbed(:item) }。build_stubbed是 FactoryBot 提供的快速存根方法,它会模拟已持久化的状态,自动生成一个唯一的非nil临时id(不会真的写入数据库,但对象的id属性有值)。此时生成的 Item 有有效id,赋值后自动同步了transaction.item_id,因此校验通过。 - 手动传 Item 后异常的原因:你显式传入的属性优先级高于工厂内的同名字段定义,因此工厂原本生成 stub Item 的代码完全不会执行。你传入的是
build(:item)生成的普通未持久化对象,对应 Rails 的new方法,未存库的对象id本身就是nil,因此赋值给 Transaction 关联时,item_id不会被同步,始终为空。 create方法正常的原因:create生成的对象会真实写入数据库,拥有数据库生成的非nil真实id,满足关联同步的条件,因此外键会正常赋值。
解决方案
- 方案1:手动构建 Item 时使用
build_stubbed替代build,生成带有效临时id的存根对象:item = build_stubbed(:item) transaction = build(:transaction, item: item) - 方案2:如果需要普通的未存根 Item,手动给 Item 赋值非
nil的唯一id:item = build(:item) item.id = 12345 # 任意唯一非空值即可,可根据测试需求调整 transaction = build(:transaction, item: item) - 方案3:如果允许持久化,直接用
create生成真实存库的 Item,自带有效id:item = create(:item) transaction = build(:transaction, item: item)
内容的提问来源于stack exchange,提问作者Jonathon Nordquist
相关产品推荐
相关产品推荐

