Factory Girl (Bot) Associations

Factory Girl (Bot) Associations

In this article we will go through how to generate the data for has_one, has_many and polymorphic associations using FactoryGirl. Every association will be described with an example, so you can get the idea how to create more complex factories with no pain.

Generating the data for has_one association

Setting up has_one association is quite easy, you can define it within the factory. If the factory name is the same as the association name, the factory name can be left out. For example:

FactoryBot.define do
  factory :story do
    # story attributes
    author
  end
end

Also, you can specify a different factory and override attributes:

FactoryBot.define do
  factory :story do
    # story attributes
    association :author, factory: :user, first_name: "Jon"
  end
end

It's possible to specify different strategies for creating the association:

association :author, factory: :user, strategy: :build

Keep in mind that this won't save an associated object in the database.

Generating the data for has_many association

Generating the data for a has_many association is a bit more complicated. You can define new factory and use after(:create) callback to create a list of associations. Let's see how to do it in this example:

FactoryBot.define do

  # user factory without associated stories
  factory :user do
    # user attributes

    factory :user_with_stories do
      transient do
        stories_count 10
      end

      after(:create) do |user, evaluator|
        create_list(:stories, evaluator.stories_count, user: user)
      end
    end
  end
end

Attribute stories_count is a transient and available in attributes of the factory and in the callback via the evaluator. Now, you can create a user with stories with the option to specify how many stories we want:

create(:user_with_stories).stories.length # 10
create(:user_with_stories, stories_count: 15).stories.length # 15

Please note that every story will have a unique id, but in order to have other attributes unique, you need to generate different values for each story.

You can achieve that using the sequence as an example:

FactoryBot.define do
  factory :story do
    # story attributes
    sequence(:title) { |n| "Title#{n}" } # Unique title for every story
    association :author, factory: :user, first_name: "Jon"
  end
end

There is also an interesting gem that can help you generate unique values called faker.

Generating the data for polymorphic associations

A polymorphic association can be a bit confusing. Hopefully, this example will help you understand it better. Let's say you have next classes with polymorphic associations:

class Profile
  belongs_to :profileable, polymorphic: true
end

class Account
  belongs_to :accountable, polymorphic: true
end

class User
  has_one :profile, as: :profileable
  has_one :account, as: :accountable
end

When creating the factories for the models that have the polymorphic model, you simply create the polymorphic model in an after(:create) block and specify the polymorphicable to be the model the factory is for:

FactoryBot.define do
  factory :user, class: User do
    # user attributes
    
    after(:create) do |user|
      create(:account, accountable: user)
      create(:profile, profileable: user)
    end
  end
end

And... that's it!

Thank you for reading this article.

If you are interested in reading more interesting articles about Rails be sure to subscribe to our newsletter!

Interested in similar topics? Be sure to check our take on Rspec let vs before, Rspec Setup and FactoryGirl - create vs build vs buldstubbed.