How to create has_and_belongs_to_many associations in Factory girl

Viewed 47344

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?

11 Answers

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

Warning: Change users: [user] to :users => [user] for ruby 1.8.x

For HABTM I used traits and callbacks.

Say you have the following models:

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

You can define the Factory above:

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
Related