web-dev-qa-db-ja.com

Factory Girlでhas_and_belongs_to_manyアソシエーションを作成する方法

次の場合

class User < ActiveRecord::Base
  has_and_belongs_to_many :companies
end

class Company < ActiveRecord::Base
  has_and_belongs_to_many :users
end

双方向の関連付けを含む企業およびユーザーの工場をどのように定義しますか?これが私の試みです

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

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

今私は試します

Factory :user

当然のことながら、工場は再帰的に互いを使用して自分自身を定義するため、これは無限ループになります。

さらに驚くべきことに、私はどこでもこれを行う方法についての言及を見つけていません。必要な工場を定義するためのパターンがありますか、または根本的に間違っていることをしていますか?

118
opsb

その後、Factorygirlは更新され、この問題を解決するためのコールバックが含まれるようになりました。詳細については http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl をご覧ください。

40
opsb

ここに私のために働く解決策があります。

FactoryGirl.define do

  factory :company do
    #company attributes
  end

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

end

特定の会社が必要な場合は、この方法で工場を使用できます

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

これが誰かに役立つことを願っています。

128
Suborx

私の意見では、次のような2つの異なる工場を作成するだけです。

 Factory.define:user、:class => User do | u | 
#通常の属性初期化
 end 
 
 Factory.define: company、:class => Company do | u | 
#通常の属性初期化のみ
 end 

ユーザーのテストケースを書くときは、次のように書きます

 Factory(:user、:companies => [Factory(:company)])

それがうまくいくことを願っています。

22
Ashish

提供されたウェブサイトで上記のケースの例を見つけることができませんでした。 (1:Nとポリモーフィックな関連付けのみ、habtmはなし)。同様のケースがあり、私のコードは次のようになります。

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

私のために働いたのは、工場を使用するときに関連付けを設定することでした。あなたの例を使用して:

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

警告:ユーザーの変更:[user] to:users => [user] for Ruby 1.8.x

3
Artur79

この方法で見つけた素敵で冗長:

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

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

Rails 5:

_has_and_belongs_to_many_関連付けを使用する代わりに、_has_many :through_関連付けを考慮する必要があります。

この関連付けのユーザーファクトリは次のようになります。

_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
_

同様の方法で会社の工場を作成できます。

両方のファクトリを設定したら、_user_with_companies_を使用して_companies_count option_ファクトリを作成できます。ここでは、ユーザーが属する会社の数を指定できます:create(:user_with_companies, companies_count: 15)

ファクトリーガールズアソシエーションはこちら に関する詳細な説明を見つけることができます。

0
Nesha Zoric

HABTMでは、特性とコールバックを使用しました

次のモデルがあるとします。

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

上記のファクトリを定義

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

まず、habtmの代わりにhas_many:throughを使用することを強くお勧めします(これについては here を参照してください)。そのため、次のような結果になります。

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

この後、両側にhas_manyアソシエーションがあり、factory_girlであなたがしたようにそれらに割り当てることができます。

0
Milan Novota

新しいファクトリを定義し、after(:create)コールバックを使用して関連付けのリストを作成できます。この例でそれを行う方法を見てみましょう:

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

属性Companies_countは一時的なものであり、ファクトリーの属性およびエバリュエーターを介したコールバックで使用可能です。これで、必要な会社数を指定するオプションを使用して、会社を持つユーザーを作成できます。

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