在 factory_girl 中填充与儿童的关联
Posted
技术标签:
【中文标题】在 factory_girl 中填充与儿童的关联【英文标题】:Populating an association with children in factory_girl 【发布时间】:2011-02-25 14:39:30 【问题描述】:我有一个模型Foo
,它有_many 'Bar'。我为这些对象中的每一个都有一个 factory_girl 工厂。 Bar 的工厂与 Foo 有关联;它会在创建 Bar 时实例化一个 Foo。
我想要一个创建包含 Bar 的 Foo 的工厂。理想情况下,此 Bar 将通过 :bar 工厂创建,并尊重用于创建 Foo 的构建策略(创建/构建)。
我知道我可以调用 :bar 工厂,然后从新 Bar 中获取 Foo 引用。我想避免这种情况;在我的测试用例中,重要的对象是 Foo;调用酒吧工厂似乎有点迂回。此外,我可以看到需要具有多个 Bars 的 Foo。
这在 factory_girl 中可行吗?您如何在父级中定义这种关系?
【问题讨论】:
【参考方案1】:您可以同时使用association
方法:
Factory.define :foo do |f|
# ...
f.association :bar
end
如果这不起作用,您可以使用回调手动关联它们。这是我的一个应用程序中的一个示例:
Factory.define :live_raid do |raid|
end
Factory.define :live_raid_with_attendee, :parent => :live_raid do |raid|
raid.after_create |r| Factory(:live_attendee, :live_raid => r)
end
【讨论】:
第一个语法在我的代码中导致堆栈溢出/无限递归。第二种语法效果很好,只是它不遵守构建策略。【参考方案2】:Factory.after_ hooks
似乎是成功执行此操作的唯一方法。我已经找到了一种无需重复代码即可维护构建策略的方法:
Factory.define :foo do |f|
f.name "A Foo"
f.after(:build) |foo|
foo.bars << Factory.build(:bar, :foo => foo)
f.after(:create) |foo|
foo.bars.each |bar| bar.save!
end
documentation 声明如果使用:create
构建策略,after_build
将在after_create
之前调用。如果使用:build
,那么只调用after_build
,大家就开心了。
我还创建了一个抽象的通用版本at this gist 以保持干燥。
【讨论】:
很难相信这是最好的方法,但似乎仍然如此。对此答案投了赞成票。 你如何使用你的 gist 版本?将它整合到 Rails 应用程序中的最佳方式是什么? 如here 所述,使用<<
添加关联会保留更改。为避免这种情况,after(:build)
应为 foo.association(:bars).add_to_target(Factory.build(:bar, :foo => foo) )
【参考方案3】:
FactoryGirl 现在有一个可用于关联的:method => :build
选项,它将构建关联对象而不是创建它。
#64: Building an object creates associations
【讨论】:
【参考方案4】:FactoryGirl 4.3.0 在父对象上调用 build
时在关联上调用 save!
,我认为这不是正确的行为。
在挖掘 FactoryGirl 代码后,将 strategy: :build
添加到工厂中的关联定义现在似乎无需调用 save!
即可创建我的关联。
【讨论】:
【参考方案5】:使用factory_girl-4.5.0
,在父对象工厂中创建n个子对象
FactoryGirl.define do
factory :foo do
name "test"
after(:build) do |instance|
n.times instance.bars << FactoryGirl.create(:bar)
end
end
end
【讨论】:
以上是关于在 factory_girl 中填充与儿童的关联的主要内容,如果未能解决你的问题,请参考以下文章
访问 *other* 工厂中的 factory_girl 工厂