ruby 更新FactoryBot trait中的关联对象

acruukt9  于 2023-10-18  发布在  Ruby
关注(0)|答案(3)|浏览(169)

样品工厂

FactoryBot.define do
  factory :fruit do
    name { "Kiwi" }
    status { "available" }
    store { Store.first }
  end

  trait :unaccessible do
    status { "unaccessible" }
    store { status: "closed", hours_before_open: 2 }
  end
end

在trait块中,我一直在努力寻找一种方法来更新关联Store对象的属性。在documentation的Traits部分没有找到示例。也没有找到任何例子在这里搜索SO和谷歌搜索。这甚至可能吗?

8cdiaqws

8cdiaqws1#

我相信你也应该能够覆盖trait中的关联,就像这样:

FactoryBot.define do
  factory :fruit do
    name { "Kiwi" }
    status { "available" }
    store # assumes a factory :store
  end

  trait :unaccessible do
    status { "unaccessible" }
    association :store, status: "closed", hours_before_open: 2
  end
end

那么你就不需要执行额外的数据库写入来更新after create中的store对象。

ax6ht2ek

ax6ht2ek2#

使用after块覆盖这些属性。

bogh5gae

bogh5gae3#

我更喜欢海伦的回答!它很简单,避免了对数据库的额外写入。还建议将trait定义移到工厂定义中。否则,它就是一个全局trait,可能会与其他同名的全局trait冲突。
为了好玩,这里有一个使用transient的替代方案。它定义了一些属性,你可以用这些属性来参数化工厂中的东西,这些属性不会在生成的对象上设置。

FactoryBot.define do
  factory :fruit do
    transient do
      # Let this factory accept an extra attribute called "store_attrs"
      # which we'll use to parameterize the construction of "store".
      store_attrs { {} }
    end

    name { "Kiwi" }
    status { "available" }
    store { create(:store, **store_attrs) }

    trait :unaccessible do
      status { "unaccessible" }
      store_attrs { { status: "closed", hours_before_open: 2 } }
    end
  end
end

然后,您可以在规范中使用store_attrs来微调存储,而无需定义更多trait:

let(:fruit) { FactoryBot.create(:fruit, store_attrs: { status: "renovating" }) }
# Note that `fruit.store_attrs` doesn't exist.

虽然在这个例子中,你可以只在一个单独的let中定义商店:

let(:shop) { FactoryBot.create(:shop, status: "renovating") }
let(:fruit) { FactoryBot.create(:fruit, shop: shop) }

相关问题