Factory Girlでhas_and_belongs_to_many関連付けを作成する方法


119

次の場合

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

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

より驚くべきことに、これをどこで行うかについての言及はどこにも見つかりませんでした。必要なファクトリを定義するためのパターンはありますか、それとも根本的に間違っていることをしていますか?

回答:


132

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

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])

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


4
ありがとう、すべての解決策の中で最もきちんとした。
Mik、2012年

ありがとうございました。これにより、何時間もの欲求不満の後で私の問題が解決しました。
Tony Beninate、2012年

これは、すべてのファクトリーが1つのファイルに含まれている場合にのみ機能します。したがって、以下の@opsbで言及されているソリューションの方が優れているようです。
2013

40

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


37
リンクは実際にはhas_and_belongs_to_manyの処理方法を示していません...これを行う方法はわかりません...
dmonopoly

3
:コールバック構文は今に変更されたafter(:create)代わりにafter_create、ここで述べたように、工場の女の子に:stackoverflow.com/questions/15003968/...
マイケルYagudaev

22

私の意見では、次のような2つの異なるファクトリを作成するだけです。

 Factory.define:user、:class =>ユーザーは| u |
  #通常の属性の初期化
 終わり

 Factory.define:company、:class => Company do | u |
  #通常の属性の初期化
 終わり

ユーザーのテストケースを書くときは、このように書いてください

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

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


2
おかげでこれは私が働くことができる唯一の例です。工場の女の子はhabtmの大きな頭痛の種です。
jspooner 2011

これは、FactoryGirlの最近のバージョンでは機能しません(Rails 3を考えています)
Raf

9

提供されたWebサイトで、上記のケースの例を見つけることができませんでした。(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

3
ゼロ以外のユーザー数の検証がある場合はどうなりますか?
dfens

5

私にとってうまくいったことは、工場を使用するときに協会を設定することでした。あなたの例を使用して:

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

company.users << user 
company.save! 

4

この方法は見事で冗長です:

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

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

1
foos { |a| [a.association(:foo)] }とても助かります!ありがとうございました!
モンテイロブレナ2018年

3
  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]を:users => [user]に変更して、ruby 1.8.xの場合


4
それはすべきではない: after_create { |company, evaluator| FactoryGirl.create_list(:user, evaluator.users_count, companies: [company]) }
Raf

0

まず第一に、habtmの代わりにhas_many:throughを使用することを強くお勧めします(これについてはこちらをご覧ください)。したがって、次のような結果になります。

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アソシエーションがあり、factor_girlでそれらを割り当てることができます。


3
Employment belongs_to :userそれEmployment belongs_to :companyは、1つの企業と1つのユーザーを接続する結合モデルではないのですか?
Daniel Beardsley、2010年

5
あなたが言及した投稿をざっと読んだときの私の結論は、habtmとhas_many:throughのどちらを選択するかは、ユースケースに依存するということです。本当の「勝者」はいない。
auralbee

まあ、hmtを使用する場合の唯一のオーバーヘッドは、IDをスルーテーブルで定義する必要があることです。今のところ、問題になるような状況は想像できません。habtmが役に立たないとは言いませんが、99%のユースケースでは、(その利点のため)hmtを使用する方が理にかなっています。
ミラノノボタ

6
-1は、HMTに「利点」が多いからといって、それらの利点が必要な場合にのみ使用することを意味します。私は現在、開発者がHABTMで十分であるいくつかのケースでHMTを使用していたプロジェクトに取り組んでいるので、ペットピーブです。したがって、コードベースは大きく、複雑で、直感的ではなく、そのためにSQL結合が遅くなります。したがって、可能な場合はHABTMを使用してから、各関連付けに関する追加情報を格納するために個別の結合モデルを作成する必要がある場合にのみ、HMTを使用してください。
sbeam

0

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

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

-1

新しいファクトリを定義し、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

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

create(:user_with_companies).companies.length # 10
create(:user_with_companies, companies_count: 15).companies.length # 15
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.