web-dev-qa-db-fra.com

Comment installer une usine dans FactoryGirl avec l'association has_many

Est-ce que quelqu'un peut me dire si je vais juste dans la mauvaise configuration?

J'ai les modèles suivants qui ont has_many.through associations:

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

J'utilise Rails 3.1.rc4, FactoryGirl 2.0.2, factory_girl_Rails 1.1.0 et rspec. Voici mon test de vérification de base rspec rspec pour l’usine :listing:

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

Voici 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

Les usines :listing_feature et :feature sont configurées de la même manière.
Si la ligne association :features est commentée, tous mes tests réussissent.
Lorsqu'il est 

association :features, :factory => :feature

le message d'erreur est undefined method 'each' for #<Feature>, ce qui me paraissait logique, car listing.features renvoie un tableau. Alors je l'ai changé pour 

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

et l'erreur que je reçois maintenant est ArgumentError: Not registered: features Est-il simplement déconseillé de générer des objets d'usine de cette façon ou qu'est-ce qui me manque? Merci beaucoup pour toute contribution!

81
Tonys

La création de ce type d’associations nécessite l’utilisation des rappels de FactoryGirl.

Vous trouverez ici un ensemble d'exemples parfaits.

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

Pour ramener à la maison à votre exemple.

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
52
winfred

Vous pouvez également utiliser un bloc et ignorer le mot clé association. Cela permet de construire des objets sans enregistrer dans la base de données (sinon, une association has_many enregistrera vos enregistrements dans la base de données, même si vous utilisez la fonction build au lieu de create).

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

J'ai essayé différentes approches et c'est celle qui a le mieux fonctionné pour moi (adaptée à votre cas)

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
20
Dave Sag

Vous pouvez utiliser trait:

FactoryGirl.define do
  factory :listing do
    ...

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

Avec callback, si vous avez besoin de créer une base de données:

...

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

Utilisez dans vos spécifications comme ceci:

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

Cela éliminera les doublons dans vos usines et sera plus réutilisable.

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

17
ehoffmann

Voici comment j'ai installé le mien:

# 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

Et puis dans vos tests, vous pouvez faire:

@preference_set = FactoryGirl.create(:preference_set_with_preferences)

J'espère que cela pourra aider.

0
rii