如何为相互验证的模型编写工厂?

How can I write factories for Models that validate each other?

Parent Class:

class Parent < ActiveRecord::Base
  has_many :kids
  validates_presence_of :kids
end

孩子 Class:

class Kid < ActiveRecord::Base
  belongs_to :parent, inverse_of: :kids
  validates :parent, presence: true
end

Parent工厂:

FactoryGirl.define do
  factory :parent do
    2.times do
      parent.kids << FactoryGirl.create(:kid)
    end
  end
end

儿童工厂:

FactoryGirl.define do
  factory :kid do
    parent
  end
end

此配置会导致无限循环。我尝试了 FactoryGirl.build、FactoryGirl.create、after(:build)、before(:create)、关联、建造第二个虚拟工厂等的所有组合

编写这些工厂的最佳方式是什么?我犯了一个愚蠢的错误吗?

似乎其他人也遇到过这个问题:http://www.rubyfocus.biz/blog/2010/12/18/factory_girl_association_hierarchies_inverse_of.html

Ruby2.2.1,Rails4.1.5,rspec-rails3.0.2,factory_girl_rails4.4.1.

你发的页面的答案其实很好,所以我引用一下。

你实际上不能那样做。而且使用hooks的建议也是有限的

If you need to build object hierarchies where the objects have validation rules against each other, you'll run into this inverse_of issue with belongs_to associations.

ActiveRecord generally will be able to save an object hierarchy correctly if it's constructed entirely in memory and then saved via the topmost ancestor. You can simulate this behavior in some cases by using Factory.build and adding after_build hooks inside the Factory definition to set up dependent objects. This does not work well for more than one level of hierarchy.

The last resort is to set up your own helper methods and construct object hierarchies in memory, assign the dependencies, then call save on the topmost parent. It's not as elegant as the Factory invocation, but it can help to de-clutter a bunch of setup code to work around Factory and ActiveRecord quirks.

对于我的用例,这有效:

父工厂:

FactoryGirl.define do
  factory :parent do
    2.times do
      parent.kids << FactoryGirl.create(:kid)
    end
  end
end

儿童工厂:

FactoryGirl.define do
  factory :kid do
    parent {Owner.new}
  end
end

此模式只是将一个新的、未使用的所有者对象分配给 Kid 工厂(以通过验证)。由于 Parent has_many Kids 和 Kid 可以有多个 Parents,因此调用任何一个工厂时都不会发生冲突。在您的规范中,您可以覆盖默认关联以测试所需的行为。

实际上,如果其中一个模型没有经过太多测试,您也可以不为其中一个模型创建工厂;您必须为每个规范创建 "new" 个模型实例,如果这种情况很常见,这并不理想。

希望对某人有所帮助!