如何使用has_many关联在FactoryGirl中建立工厂


88

有人可以告诉我是否只是以错误的方式进行设置吗?

我有以下具有has_many.through关联的模型:

class Listing < ActiveRecord::Base
  attr_accessible ... 

  has_many :listing_features
  has_many :features, :through => :listing_features

  validates_presence_of ...
  ...  
end


class Feature < ActiveRecord::Base
  attr_accessible ...

  validates_presence_of ...
  validates_uniqueness_of ...

  has_many :listing_features
  has_many :listings, :through => :listing_features
end


class ListingFeature < ActiveRecord::Base
  attr_accessible :feature_id, :listing_id

  belongs_to :feature  
  belongs_to :listing
end

我正在使用Rails 3.1.rc4,FactoryGirl 2.0.2,factory_girl_rails 1.1.0和rspec。这是我对:listing工厂的基本rspec rspec完整性检查:

it "creates a valid listing from factory" do
  Factory(:listing).should be_valid
end

这是Factory(:listing)

FactoryGirl.define do
  factory :listing do
    headline    'headline'
    home_desc   'this is the home description'
    association :user, :factory => :user
    association :layout, :factory => :layout
    association :features, :factory => :feature
  end
end

:listing_feature:feature工厂也同样设置。
如果该association :features行被注释掉,那么我所有的测试都通过了。
几时

association :features, :factory => :feature

错误消息 undefined method 'each' for #<Feature> 对我来说很有意义,因为因为listing.features返回了一个数组。所以我改成

association :features, [:factory => :feature]

我现在得到的错误ArgumentError: Not registered: features 是这样生成工厂对象是否不明智,还是我缺少了什么?非常感谢您提供的所有信息!

Answers:


56

创建这些类型的关联需要使用FactoryGirl的回调。

可以在此处找到一组完美的示例。

https://thoughtbot.com/blog/aint-no-calla-back-girl

把它带到您的例子。

Factory.define :listing_with_features, :parent => :listing do |listing|
  listing.after_create { |l| Factory(:feature, :listing => l)  }
  #or some for loop to generate X features
end

您最终使用了关联:features,[:factory =>:feature]吗?
davidtingsu

106

或者,您可以使用块并跳过association关键字。这样就可以在不保存到数据库的情况下构建对象(否则,即使您使用build函数代替,has_many关联也会将您的记录保存到db 中create)。

FactoryGirl.define do
  factory :listing_with_features, :parent => :listing do |listing|
    features { build_list :feature, 3 }
  end
end

5
这是猫的喵。的能力,都buildcreate使它成为最通用的模式。然后使用该自定义FG构造策略gist.github.com/Bartuz/74ee5834a36803d712b7post nested_attributes_for检查控制动作时accepts_nested_attributes_for
克里斯·贝克

4
赞成,比公认的答案更具可读性和多功能性IMO
m_x 2015年

1
从FactoryBot 5开始,association关键字对父代和子代使用相同的构建策略。因此,它可以构建不保存到数据库的对象。
尼克

25

您可以使用trait

FactoryGirl.define do
  factory :listing do
    ...

    trait :with_features do
      features { build_list :feature, 3 }
    end
  end
end

使用callback,如果您需要创建数据库:

...

trait :with_features do
  after(:create) do |listing|
    create_list(:feature, 3, listing: listing)
  end
end

在这样的规格中使用:

let(:listing) { create(:listing, :with_features) }

这样可以消除工厂中的重复数据,并且可以重复使用。

https://robots.thoughtbot.com/remove-duplication-with-factorygirls-traits


20

我尝试了几种不同的方法,这对我来说是最可靠的方法(适合您的情况)

FactoryGirl.define do
  factory :user do
    # some details
  end

  factory :layout do
    # some details
  end

  factory :feature do
    # some details
  end

  factory :listing do
    headline    'headline'
    home_desc   'this is the home description'
    association :user, factory: :user
    association :layout, factory: :layout
    after(:create) do |liztng|
      FactoryGirl.create_list(:feature, 1, listing: liztng)
    end
  end
end

0

这是我的设置方法:

# Model 1 PreferenceSet
class PreferenceSet < ActiveRecord::Base
  belongs_to :user
  has_many :preferences, dependent: :destroy
end

#Model 2 Preference

class Preference < ActiveRecord::Base    
  belongs_to :preference_set
end



# factories/preference_set.rb

FactoryGirl.define do
  factory :preference_set do
    user factory: :user
    filter_name "market, filter_structure"

    factory :preference_set_with_preferences do
      after(:create) do |preference|
        create(:preference, preference_set: preference)
        create(:filter_structure_preference, preference_set: preference)
      end
    end
  end

end

# factories/preference.rb

FactoryGirl.define do
  factory :preference do |p|
    filter_name "market"
    filter_value "12"
  end

  factory :filter_structure_preference, parent: :preference do
    filter_name "structure"
    filter_value "7"
  end
end

然后在测试中,您可以执行以下操作:

@preference_set = FactoryGirl.create(:preference_set_with_preferences)

希望能有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.