2011-08-05 75 views
69

有人能告訴我,如果我只是以錯誤的方式進行安裝?如何在has_many協會的FactoryGirl中設置工廠

我有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,1.1.0 factory_girl_rails,和RSpec。下面是:listing工廠我的基本rspec的rspec的健全性檢查:

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

這裏是廠(:上市)

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難道只是不懂事的是生成工廠對象這樣,還是我缺少什麼?非常感謝任何和所有的輸入!

回答

50

創建這些類型的關聯需要使用FactoryGirl的回調。

一組完整的例子可以在這裏找到。

http://robots.thoughtbot.com/post/254496652/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 
+0

你最終使用關聯:features,[:factory =>:feature]? – davidtingsu

81

或者,您可以使用塊並跳過association關鍵字。這樣可以在不保存到數據庫的情況下構建對象(否則,即使使用build函數而不是create,has_many關聯也會將記錄保存到數據庫)。

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

這是貓的喵喵叫。 「建造」和「創造」的能力使其成爲最通用的模式。然後使用此自定義FG構建策略https://gist.github.com/Bartuz/74ee5834a36803d712b7在測試控制器操作時發佈'nested_attributes_for',accept_nested_attributes_for' –

+3

upvoted,遠比可接受的答案IMO更具可讀性和通用性 –

18

我嘗試了幾種不同的方法,這是工作最可靠,我的一個(適用於你的情況)

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) 

希望有所幫助。

11

你可以使用trait

FactoryGirl.define do 
    factory :listing do 
    ... 

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

隨着callback,如果你需要的DB創建:

... 

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