So richten Sie die Factory in FactoryGirl mit der Zuordnung has_many ein

88

Kann mir jemand sagen, ob ich das Setup nur falsch mache?

Ich habe die folgenden Modelle, die has_many.through Assoziationen haben:

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

Ich verwende Rails 3.1.rc4, FactoryGirl 2.0.2, factory_girl_rails 1.1.0 und rspec. Hier ist meine grundlegende Überprüfung der Rspec Rspec-Gesundheit für die :listingFabrik:

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

Hier ist Fabrik (: Auflistung)

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

Die :listing_featureund :featureFabriken sind ähnlich eingerichtet.
Wenn die association :featuresZeile auskommentiert ist, bestehen alle meine Tests.
Wann ist es

association :features, :factory => :feature

Die Fehlermeldung ist undefined method 'each' for #<Feature> meiner Meinung nach sinnvoll, weil weil listing.featuresein Array zurückgegeben wird. Also habe ich es geändert in

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

und der Fehler, den ich jetzt bekomme, ist: ArgumentError: Not registered: features Ist es einfach nicht sinnvoll, Fabrikobjekte auf diese Weise zu generieren, oder was fehlt mir? Vielen Dank für jede Eingabe!

Tonys
quelle

Antworten:

56

Um solche Assoziationen zu erstellen, müssen die Rückrufe von FactoryGirl verwendet werden.

Eine perfekte Auswahl an Beispielen finden Sie hier.

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

Um es zu Ihrem Beispiel nach Hause zu bringen.

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
winfred
quelle
Haben Sie am Ende Assoziation: Features, [: Factory =>: Feature] verwendet?
Davidtingsu
106

Alternativ können Sie einen Block verwenden und das associationSchlüsselwort überspringen . Auf diese Weise können Objekte erstellt werden, ohne in der Datenbank gespeichert zu werden (andernfalls speichert eine has_many-Zuordnung Ihre Datensätze in der Datenbank, auch wenn Sie die buildFunktion anstelle von verwenden create).

FactoryGirl.define do
  factory :listing_with_features, :parent => :listing do |listing|
    features { build_list :feature, 3 }
  end
end
JellicleCat
quelle
5
Dies ist der Miau der Katze. Die Fähigkeit zu beidem buildund createmacht es zum vielseitigsten Muster. Verwenden Sie dann diese benutzerdefinierte FG-Build-Strategie gist.github.com/Bartuz/74ee5834a36803d712b7 , post nested_attributes_forum Controller-Aktionen zu testen, dieaccepts_nested_attributes_for
Chris Beck
4
upvoted, weitaus lesbarer und vielseitiger als die akzeptierte Antwort IMO
m_x
1
Ab FactoryBot 5 verwendet das associationSchlüsselwort dieselbe Erstellungsstrategie für Eltern und Kinder. So können Objekte erstellt werden, ohne in der Datenbank gespeichert zu werden.
Nick
25

Sie könnten verwenden trait:

FactoryGirl.define do
  factory :listing do
    ...

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

Mit callback, wenn Sie eine DB-Erstellung benötigen:

...

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

Verwenden Sie in Ihren Spezifikationen wie folgt:

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

Dadurch werden Doppelspurigkeiten in Ihren Fabriken beseitigt und können wiederverwendet werden.

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

ehoffmann
quelle
20

Ich habe ein paar verschiedene Ansätze ausprobiert und dieser hat für mich am zuverlässigsten funktioniert (angepasst an Ihren Fall).

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
Dave Sag
quelle
0

So habe ich meine eingerichtet:

# 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

Und dann können Sie in Ihren Tests Folgendes tun:

@preference_set = FactoryGirl.create(:preference_set_with_preferences)

Hoffentlich hilft das.

rii
quelle