Factory_bot: Many to Many / :has_many :through

Created on 13 Jul 2013  路  1Comment  路  Source: thoughtbot/factory_bot

I have been pouring over documentation for last few hours on how to properly establish a factory set with a many-to-many relationship in rails. I keep running into old syntax from previous FactoryGirl versions mixed together and it just isn't working out between us.

From the deepest depths of my heart I would be grateful if someone/s could instruct myself and those on the lost path that accompany me on how to set up this scenario given the following two resources and their link:

class User < ActiveRecord::Base
  has_many :user_registrations
  has_many :registrations, through: :user_registrations
end

class UserRegistration < ActiveRecord::Base
  belongs_to :user
  belongs_to :registration
end

class Registration < ActiveRecord::Base
  has_many :user_registrations
  has_many :users, through: :user_registrations
end

This is what I have so far, as per the documentation found here for a has_one has_many relationship. This is as close as I've come so far into any real progress.

FactoryGirl.define do

  factory :registration do
    user
  end

  factory :user, class: User do
    sequence(:email) { |n| "foo#{n}@example.com" }
    password "password"

    factory :user_with_registrations do

      ignore do
        registrations_count 1
      end

      after(:create) do |user, evaluator|
        registrations FactoryGirl.create_list(:registration, evaluator.registrations_count, user: user)
      end
    end
  end
end

Which fails in the following manner, which I realize is because this setup is stated to be for a one-to-many relationship.

1) User Login Success
     Failure/Error: user = FactoryGirl.create(:user_with_registrations)
     NoMethodError:
       undefined method `user=' for #<Registration:0x007fc48e2ca768>
     # ./spec/factories.rb:18:in `block (4 levels) in <top (required)>'

So the question is:
What is the correct way to define a factory set for the Many to Many scenario?

image

Help would be very much appreciated. Thanks!

Most helpful comment

I am not sure if this will answer your question, but here are the two ways I usually create a has_many :through relationship in Factory Girl. However I am pretty new to Factory Girl, so I am not sure if it's the best way.

require 'factory_girl'

FactoryGirl.define do
  factory :user do
    name 'Pete'
  end

  factory :registration do
    title 'Summer Class'
  end

  factory :user_registration do
    user
    registration
  end
end

Here are the two different ways being tested

require 'spec_helper'

describe "Connecting Users to Registrations through 2 Factories" do
  before :each do
    @user = create(:user)
    @registration = create(:registration)
    @user.registrations << @registration
  end

  it "should associate the user with the registration" do
    expect(@user.name).to eq 'Pete'
    expect(@registration.title).to eq 'Summer Class'
    expect(@user.registrations.length).to eq 1
  end

  describe "Connecting Users to Registrations through 1 Factory" do
    before :each do
      @user_and_registration = create(:user_registration)
    end

    it "should create a new user and new registration and associate them" do
      expect(@user_and_registration.user.name).to eq 'Pete'
      expect(@user_and_registration.registration.title).to eq 'Summer Class'
    end
  end
end

Hopefully this helps

>All comments

I am not sure if this will answer your question, but here are the two ways I usually create a has_many :through relationship in Factory Girl. However I am pretty new to Factory Girl, so I am not sure if it's the best way.

require 'factory_girl'

FactoryGirl.define do
  factory :user do
    name 'Pete'
  end

  factory :registration do
    title 'Summer Class'
  end

  factory :user_registration do
    user
    registration
  end
end

Here are the two different ways being tested

require 'spec_helper'

describe "Connecting Users to Registrations through 2 Factories" do
  before :each do
    @user = create(:user)
    @registration = create(:registration)
    @user.registrations << @registration
  end

  it "should associate the user with the registration" do
    expect(@user.name).to eq 'Pete'
    expect(@registration.title).to eq 'Summer Class'
    expect(@user.registrations.length).to eq 1
  end

  describe "Connecting Users to Registrations through 1 Factory" do
    before :each do
      @user_and_registration = create(:user_registration)
    end

    it "should create a new user and new registration and associate them" do
      expect(@user_and_registration.user.name).to eq 'Pete'
      expect(@user_and_registration.registration.title).to eq 'Summer Class'
    end
  end
end

Hopefully this helps

Was this page helpful?
0 / 5 - 0 ratings