2011-08-05 9 views
69

Czy ktoś może mi powiedzieć, że jeśli chodzi o konfigurację w niewłaściwy sposób?Jak założyć fabrykę w FactoryGirl z has_many association

mam następujące modele, które mają has_many.through skojarzenia:

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 

Używam Rails 3.1.rc4, FactoryGirl 2.0.2, 1.1.0 i factory_girl_rails rspec. Tu jest mój podstawowy rspec rspec poczytalność czek na fabryce :listing:

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

Oto Factory (: aukcja)

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 

W :listing_feature i :feature fabryki są w podobny setup.
Jeśli linia association :features jest zakomentowana, wszystkie testy zakończą się pomyślnie.
Gdy jest

association :features, :factory => :feature 

komunikat o błędzie jest undefined method 'each' for #<Feature> co uważałem, że dla mnie sens, ponieważ z powodu listing.features zwraca tablicę. Więc zmieniłem go

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

a błąd mam teraz jest ArgumentError: Not registered: features Czy to po prostu nie rozsądne, aby być generowanie obiektów fabryki w ten sposób, albo co mi brakuje? Dziękuję bardzo za wszelkie dane wejściowe!

Odpowiedz

50

Tworzenie tego rodzaju powiązań wymaga użycia oddzwonień FactoryGirl.

Doskonały zestaw przykładów można znaleźć tutaj.

http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl

celu dostosowania go do domu na swoim przykładzie.

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

nie skończy się za pomocą asocjacji: cechy, [: fabryka =>: funkcja]? – davidtingsu

81

Alternatywnie, można użyć bloku i pominąć słowa kluczowego association. Dzięki temu można budować obiekty bez zapisywania w bazie danych (w przeciwnym razie skojarzenie has_many spowoduje zapisanie rekordów w bazie danych, nawet jeśli użyje się funkcji build zamiast create).

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

To jest kocie miau. Zdolność do "budowania" i "tworzenia" sprawia, że ​​jest to najbardziej uniwersalny wzór. Następnie użyj tej niestandardowej strategii budowania FG: https://gist.github.com/Bartuz/74ee5834a36803d712b7 do "post nested_attributes_for" podczas testowania akcji kontrolera, który 'accepts_nested_attributes_for' –

+3

przejął, dużo bardziej czytelny i wszechstronny niż zaakceptowana odpowiedź IMO –

18

Próbowałem kilka różnych podejść i to jest taki, który pracował najbardziej wiarygodny dla mnie (dostosowany do przypadku)

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

Oto jak moja konfiguracja:

# 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 

A następnie w swoich testach możesz wykonać:

@preference_set = FactoryGirl.create(:preference_set_with_preferences) 

Nadzieję, że pomaga.

11

Można użyć trait:

FactoryGirl.define do 
    factory :listing do 
    ... 

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

Z callback, jeśli trzeba tworzenie DB:

... 

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

wykorzystania w specyfikacji tak:

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

To usunie powielania w swoich fabrykach i być bardziej przydatnym do ponownego użycia.

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

Powiązane problemy