web-dev-qa-db-fra.com

Comment créer des associations has_and_belongs_to_many dans Factory girl

Compte tenu de ce qui suit

class User < ActiveRecord::Base
  has_and_belongs_to_many :companies
end

class Company < ActiveRecord::Base
  has_and_belongs_to_many :users
end

comment définissez-vous les usines pour les entreprises et les utilisateurs, y compris l'association bidirectionnelle? Voici ma tentative

Factory.define :company do |f|
  f.users{ |users| [users.association :company]}
end

Factory.define :user do |f|
  f.companies{ |companies| [companies.association :user]}
end

maintenant j'essaye 

Factory :user

Peut-être sans surprise, cela aboutit à une boucle infinie puisque les usines s’utilisent de manière récursive pour se définir.

Plus surprenant, je n’ai pas trouvé la moindre explication sur la manière de procéder, y at-il un modèle pour définir les usines nécessaires ou je fais quelque chose de fondamentalement faux? 

118
opsb

Depuis, Factorygirl a été mis à jour et inclut désormais des rappels pour résoudre ce problème. Jetez un coup d'oeil à http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl pour plus d'informations.

40
opsb

Voici la solution qui fonctionne pour moi.

FactoryGirl.define do

  factory :company do
    #company attributes
  end

  factory :user do
   companies {[FactoryGirl.create(:company)]}
   #user attributes
  end

end

si vous avez besoin d'une compagnie spécifique, vous pouvez utiliser l'usine de cette façon

company = FactoryGirl.create(:company, #{company attributes})
user = FactoryGirl.create(:user, :companies => [company])

J'espère que cela sera utile à quelqu'un.

126
Suborx

À mon avis, il suffit de créer deux usines différentes comme:

 Factory.define: utilisateur,: classe => utilisateur do | u | 
 # Initialisation normale des attributs 
 fin

 Factory.define: société,: classe => société do | u | 
 # Initialisation normale des attributs 
 fin

Lorsque vous écrivez les cas de test pour l'utilisateur, écrivez simplement comme ceci

 Usine (: utilisateur,: entreprises => [Usine (: entreprise)]) 

J'espère que ça va marcher.

22
Ashish

Je n'ai pas trouvé d'exemple pour le cas mentionné ci-dessus sur le site Web fourni. (Seulement 1: N et associations polymorphes, mais pas d'habtm). J'ai eu un cas similaire et mon code ressemble à ceci:

Factory.define :user do |user|
 user.name "Foo Bar"
 user.after_create { |u| Factory(:company, :users => [u]) }
end

Factory.define :company do |c|
 c.name "Acme"
end
9
auralbee

Ce qui a fonctionné pour moi, c’était de définir l’association lors de l’utilisation de l’usine. En utilisant votre exemple:

user = Factory(:user)
company = Factory(:company)

company.users << user 
company.save! 
5
Larry Kooper
  factory :company_with_users, parent: :company do

    ignore do
      users_count 20
    end

    after_create do |company, evaluator|
      FactoryGirl.create_list(:user, evaluator.users_count, users: [user])
    end

  end

Attention: Modifier les utilisateurs: [utilisateur] en: utilisateurs => [utilisateur] pour Ruby 1.8.x

3
Artur79

Trouvé ainsi Nice et verbeux:

FactoryGirl.define do
  factory :foo do
    name "Foo" 
  end

  factory :bar do
    name "Bar"
    foos { |a| [a.association(:foo)] }
  end
end
3
pasha.zhukov

Mise à jour pour Rails 5:

Au lieu d'utiliser l'association has_and_belongs_to_many, vous devriez envisager: l'association has_many :through.

La fabrique d'utilisateurs pour cette association ressemble à ceci:

FactoryBot.define do
  factory :user do
    # user attributes

    factory :user_with_companies do
      transient do
        companies_count 10 # default number
      end

      after(:create) do |user, evaluator|
         create_list(:companies, evaluator.companies_count, user: user)
      end
    end
  end
end

Vous pouvez créer l’usine de la société de la même manière.

Une fois les deux usines définies, vous pouvez créer une usine user_with_companies avec companies_count option. Ici, vous pouvez spécifier le nombre de sociétés auxquelles l'utilisateur appartient: create(:user_with_companies, companies_count: 15)

Vous pouvez trouver des explications détaillées sur les associations de filles dans les usines ici .

0
Nesha Zoric

Pour HABTM, j’ai utilisé des traits et des rappels .

Disons que vous avez les modèles suivants:

class Catalog < ApplicationRecord
  has_and_belongs_to_many :courses
  …
end
class Course < ApplicationRecord
  …
end

Vous pouvez définir l’usine ci-dessus :

FactoryBot.define do
  factory :catalog do
    description "Catalog description"
    …

    trait :with_courses do
      after :create do |catalog|
        courses = FactoryBot.create_list :course, 2

        catalog.courses << courses
        catalog.save
      end
    end
  end
end
0
lucasarruda

Tout d'abord, je vous encourage fortement à utiliser has_many: through au lieu de habtm (pour en savoir plus sur ce ici ), vous obtiendrez ainsi quelque chose du genre

Employment belongs_to :users
Employment belongs_to :companies

User has_many :employments
User has_many :companies, :through => :employments 

Company has_many :employments
Company has_many :users, :through => :employments

Après cela, vous aurez beaucoup d'associations des deux côtés et vous pourrez les affecter à factory_girl de la manière que vous avez utilisée.

0
Milan Novota

Vous pouvez définir une nouvelle fabrique et utiliser après le rappel (: create) pour créer une liste d'associations. Voyons comment faire dans cet exemple:

FactoryBot.define do

  # user factory without associated companies
  factory :user do
    # user attributes

    factory :user_with_companies do
      transient do
        companies_count 10
      end

      after(:create) do |user, evaluator|
        create_list(:companies, evaluator.companies_count, user: user)
      end
    end
  end
end

L'attribut companies_count est transitoire et disponible dans les attributs de la fabrique et dans le rappel via l'évaluateur. Maintenant, vous pouvez créer un utilisateur avec des sociétés avec la possibilité de spécifier le nombre de sociétés que vous souhaitez:

create(:user_with_companies).companies.length # 10
create(:user_with_companies, companies_count: 15).companies.length # 15
0
Aleksandar M.