繁体   English   中英

具有has_many和has_one的多态关联的Factory Girl

[英]Factory Girl with polymorphic association for has_many and has_one

我目前正在开发一个项目,我想用工厂女孩创建测试,但我无法使用多态has_many关联。 我尝试了其他文章中提到的许多不同的可能性,但它仍然无效。 我的模型看起来像这样:

class Restaurant < ActiveRecord::Base
  has_one :address, as: :addressable, dependent: :destroy
  has_many :contacts, as: :contactable, dependent: :destroy

  accepts_nested_attributes_for :contacts, allow_destroy: true
  accepts_nested_attributes_for :address, allow_destroy: true

  validates :name, presence: true
  #validates :address, presence: true
  #validates :contacts, presence: true
end

class Address < ActiveRecord::Base
  belongs_to :addressable, polymorphic: true

  # other unimportant validations, address is created valid, the problem is not here
end

class Contact < ActiveRecord::Base
  belongs_to :contactable, polymorphic: true
  # validations ommitted, contacts are created valid
end

因此,我想要为餐厅创建一个地址和联系人的工厂(在餐厅进行验证,但如果不可能,即使没有它们),但我无法这样做。 最终语法应该是:

let(:restaurant) { FactoryGirl.create(:restaurant) }

哪个还应该创建相关的地址和联系人。 我读了很多文章但总是遇到一些错误。 目前我的工厂(序列定义正确)是这样的:

factory :restaurant do
  name
  # address {FactoryGirl.create(:address, addressable: aaa)}
  # contacts {FactoryGirl.create_list(:contact,4, contactable: aaa)}
  # Validations are off, so this callback is possible
  after(:create) do |rest|
    # Rest has ID here
    rest.address = create(:restaurant_address, addressable: rest)
    rest.contacts = create_list(:contact,4, contactable: rest)
  end
end

factory :restaurant_address, class: Address do
  # other attributes filled from sequences...

  association :addressable, factory: :restaurant
  # addressable factory: restaurant
  # association(:restaurant)
end

factory :contact do
  contact_type
  value

  association :contactable, :factory => :restaurant
end

有没有办法在地址和联系人设置的测试中创建一个带有一个命令的餐馆? 因为after(:create)回调,我真的需要摆脱我的验证吗? 现状如下:

  1. 餐厅创建了名称和ID。
  2. 正在创建地址 - 所有都是正确的,它具有包括addressable_id和addressable_type在内的所有值
  3. 在那之后所有的联系人都被创造了,一切都很好,cntacts有正确的价值观。
  4. 之后,餐厅没有来自关联对象的任何ID,也没有与adddress或联系人的关联
  5. 之后,由于某种原因餐厅再次建立(可能添加这些关联?)并且它失败:我得到ActiveRecord:RecordInvalid。

我正在使用factory_girl_rails 4.3.0,ruby 1.9.3和rails 4.0.1。 我会很高兴得到任何帮助。

更新1:

为了澄清我的目标,我希望能够使用一个命令在我的规范中创建餐厅,并能够访问相关的地址和联系人,这应该在创建餐厅时创建。 让我们忽略所有的验证(我从一开始就在我的例子中注释了它们)。 当我使用after(:build)后 ,创建第一个餐馆,而不是使用餐馆ID作为addressable_id和类名作为addressable_type创建地址。 同样适用于联系人,一切都是正确的。 问题是,餐厅不知道他们(它没有地址ID或联系人),我无法从我想要的餐厅访问它们。

经过彻底的搜索后,我在这里找到了答案- stackoverflow问题 。这个答案也指向了这个要点 主要是在after(:build)回调中构建关联,然后将它们保存在after(:create)回调之后。 所以它看起来像这样:

factory :restaurant do
  name

  trait :confirmed do
    state 1
  end

  after(:build) do |restaurant|
    restaurant.address = build(:restaurant_address, addressable: restaurant)
    restaurant.contacts = build_list(:contact,4, contactable: restaurant)
  end

  after(:create) do |restaurant|
    restaurant.contacts.each { |contact| contact.save! }
    restaurant.address.save!
  end
end

我在我的rspec中也有一个错误,因为我之前使用(:每个)回调而不是之前(:all)。 我希望这个解决方案有助于某人。

问题

验证相关行列表的长度是SQL中框架的难题,因此在ActiveRecord中构建框架也是一个难题。

如果您在地址表上存储餐馆外键,您实际上无法创建一个在保存时具有地址的餐馆,因为您需要保存餐馆以获取其主键。 您可以通过在内存中构建关联对象,验证这些问题,然后在一个SQL事务中提交整个对象图,来解决ActiveRecord中的这个问题。

怎么做你要问的

你通常可以通过将事物移动到after(:build)钩子而不是after(:create) 一旦保存自己,ActiveRecord将保存其依赖的has_onehas_many关联。

您现在收到错误,因为您无法修改对象以满足after(:create)块中的验证,因为验证已在回调运行时运行。

你可以改变你的餐厅工厂看起来像这样:

factory :restaurant do
  name

  after(:build) do |restaurant|
    restaurant.address = build(:restaurant_address, addressable: nil)
    restaurant.contacts = build(:contact, 4, contactable: nil)
  end
end

nil那儿是打破工厂之间的循环关系。 如果您这样做,则无法对addressable_idcontactable_id键进行验证,因为在保存restaurant之前它们将无法使用。

备择方案

虽然您可以同时使用ActiveRecord和FactoryGirl来执行您所要求的操作,但它会设置一个不稳定的依赖项列表,这些依赖项很难理解,并且很可能导致漏洞验证或意外错误,例如您现在看到的错误。

如果您通过这种方式从餐馆模型验证联系人,因为您创建餐馆及其相应联系人的表单,您可以通过创建一个新的ActiveModel对象来表示该表单,从而为您节省很多痛苦。 您可以收集每个对象所需的属性,移动一些验证(尤其是验证联系人列表长度的验证),然后以更清晰,更不可能的方式在该表单上创建对象图。打破。

这样做的另一个好处是可以轻松地在其他测试中创建轻量级restaurant对象,而无需担心联系人或地址。 如果强制工厂每次都创建这些依赖对象,那么很快就会遇到两个问题:

  • 你的测试会非常缓慢。 每次想要与餐厅合作时创建五个相关记录将不会扩展到很远。
  • 如果您想在测试中指定不同的联系人或地址,您将不断与您的工厂抗争。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM