在 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 所述,使用&lt;&lt; 添加关联会保留更改。为避免这种情况,after(:build) 应为 foo.association(:bars).add_to_target(Factory.build(:bar, :foo =&gt; foo) )【参考方案3】:

FactoryGirl 现在有一个可用于关联的:method =&gt; :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 中填充与儿童的关联的主要内容,如果未能解决你的问题,请参考以下文章

如何通过关联为 has_many 定义工厂

访问 *other* 工厂中的 factory_girl 工厂

Rails:如果表单返回验证错误,则保持 JSON 表单字段填充

EXCEL怎么把两个相同名称后面带的内容关联一起?

使用 hasMany 关联在 ExtJS 中填充存储

如何使用 UIPickerView 在一个视图中填充不同的文本字段?