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

Gir*_*ron 2 rspec ruby-on-rails factory-bot

我目前正在开发一个项目,我想用工厂女孩创建测试,但我无法使用多态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
Run Code Online (Sandbox Code Playgroud)

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

let(:restaurant) { FactoryGirl.create(:restaurant) }
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

有没有办法在地址和联系人设置的测试中创建一个带有一个命令的餐馆?因为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或联系人),我无法从我想要的餐厅访问它们.

Gir*_*ron 7

经过彻底的搜索后,我在这里找到了答案- 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
Run Code Online (Sandbox Code Playgroud)

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