How to create has_and_belongs_to_many associations in Factory girl

46,959

Solution 1

Factorygirl has since been updated and now includes callbacks to solve this problem. Take a look at http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl for more info.

Solution 2

Here is the solution that works for me.

FactoryGirl.define do

  factory :company do
    #company attributes
  end

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

end

if you will need specific company you can use factory this way

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

Hope this will be helpful for somebody.

Solution 3

In my opinion, Just create two different factories like:

 Factory.define :user, :class => User do |u|
  # Just normal attributes initialization
 end

 Factory.define :company, :class => Company do |u|
  # Just normal attributes initialization
 end

When you write the test-cases for user then just write like this

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

Hope it will work.

Solution 4

I couldn´t find an example for the above mentioned case on the provided website. (Only 1:N and polymorphic assocations, but no habtm). I had a similar case and my code looks like this:

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

Solution 5

What worked for me was setting the association when using the factory. Using your example:

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

company.users << user 
company.save! 
Share:
46,959
opsb
Author by

opsb

Updated on July 26, 2020

Comments

  • opsb
    opsb almost 4 years

    Given the following

    class User < ActiveRecord::Base
      has_and_belongs_to_many :companies
    end
    
    class Company < ActiveRecord::Base
      has_and_belongs_to_many :users
    end
    

    how do you define factories for companies and users including the bidirectional association? Here's my attempt

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

    now I try

    Factory :user
    

    Perhaps unsurprisingly this results in an infinite loop as the factories recursively use each other to define themselves.

    More surprisingly I haven't found a mention of how to do this anywhere, is there a pattern for defining the necessary factories or I am doing something fundamentally wrong?

  • Daniel Beardsley
    Daniel Beardsley about 14 years
    Shouldn't that be Employment belongs_to :user and Employment belongs_to :company with the join model connecting one Company with one User?
  • auralbee
    auralbee over 13 years
    My conclusion from a quick read through the post you mentioned is that it depends on your use case whether to choose habtm or has_many :through. There is no real "winner".
  • Milan Novota
    Milan Novota over 13 years
    Well, the only overhead when using hmt is that you have to have id defined on the through table. Right now, I can't imagine a situation when that could cause any problem. I don't say that habtm is of no use, just that in 99% use cases it makes more sense to use hmt (because of its advantages).
  • dfens
    dfens about 13 years
    what if there is validation of non-zero user count ?
  • dmonopoly
    dmonopoly almost 13 years
    The link doesn't actually say how to handle has_and_belongs_to_many... I don't see how to do this...
  • blakkheartt12
    blakkheartt12 almost 13 years
    Thanks this is the only example I could get working. Factory girl is a big headache for habtm.
  • Mik
    Mik about 12 years
    Thank you, most neat of all solutions.
  • sbeam
    sbeam about 12 years
    -1, just because HMT has more 'advantages' only means you should use it if you NEED those advantages. Pet peeve, because I'm working on a project now where the developer used HMT in several cases where HABTM would have sufficed. The codebase is therefore larger, more complex, less intuitive and produces slower SQL joins because of it. So, use HABTM when you can, then when you NEED to create a separate join model to store extra info about each association, only then use HMT.
  • Tony Beninate
    Tony Beninate over 11 years
    Thank you. This has fixed my problem after hours of frustration.
  • Raf
    Raf over 11 years
    Shouldn't it be : after_create { |company, evaluator| FactoryGirl.create_list(:user, evaluator.users_count, companies: [company]) } ?
  • Raf
    Raf over 11 years
    This no longer works with recent versions of FactoryGirl (i'm thinking Rails 3)
  • spier
    spier almost 11 years
    This only works for me when all the factories are in one file which is quite undesirable. Therefore the solution mentioned by @opsb below seems to be better.
  • Michael Yagudaev
    Michael Yagudaev over 10 years
    Callback syntax has now been changed to: after(:create) instead of after_create in factory girl as mentioned here: stackoverflow.com/questions/15003968/…
  • monteirobrena
    monteirobrena about 6 years
    foos { |a| [a.association(:foo)] } helps me a lot! Thank you!