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

时间:2015-05-16 02:23:58

标签: ruby-on-rails ruby-on-rails-4 rspec factory-bot

父类:

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

Kid Class:

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

家长工厂:

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

Kid Factory:

FactoryGirl.define do
  factory :kid do
    parent
  end
end

此配置会导致无限循环。我已经尝试了FactoryGirl.build,FactoryGirl.create,(:build)之后,(:create),协会,建立第二个虚拟工厂等的每个组合。

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

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

Ruby 2.2.1,Rails 4.1.5,rspec-rails 3.0.2,factory_girl_rails 4.4.1。

2 个答案:

答案 0 :(得分:0)

您发布的页面的答案实际上非常好,所以我在这里引用它。

你实际上不能这样做。并且使用钩子的建议也是有限的。

  

如果需要构建对象所具有的对象层次结构   相互验证规则,你会遇到这个逆向   与belongs_to协会有关。

     

ActiveRecord通常可以保存对象层次结构   正确的,如果它完全在内存中构建,然后通过保存   最顶级的祖先。您可以在某些情况下模拟此行为   使用Factory.build并在Factory中添加after_build挂钩   定义以设置依赖对象。这不适合   多层次的层次结构。

     

最后的方法是设置自己的帮助方法和构造   内存中的对象层次结构,分配依赖项,然后调用save   在最顶层的父母。它没有Factory调用那么优雅,   但它可以帮助解决一堆设置代码   解决工厂和ActiveRecord的怪癖。

答案 1 :(得分:0)

对于我的用例,这有效:

家长工厂:

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

Kid Factory:

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

此模式只是将一个新的未使用的所有者对象分配给Kid工厂(以传递验证)。由于父母has_many孩子和孩子可以有很多父母,所以在致电任何一家工厂时都没有冲突。在您的规范中,您可以覆盖默认关联以测试所需的行为。

实际上,如果其中一个模型没有经过大量测试,你也可以不为其中一个模型创建工厂;你必须为每个规范创建模型的“新”实例,如果这种情况很常见,这是不理想的。

希望能帮助别人!