Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an association in FactoryGirl with a value lazy-evaluated from another FactoryGirl association

Is it possible to use an association as the value for another association in a trait?

Let me describe a (simplified) example. I have 3 models

  • User
  • Forum (belongs_to :forum)
  • Thread (belongs_to :forum, belongs_to :user)

Please note that Thread contains an user_id, it does not belong to User through Forum (at the time being, I can't change such constraint).

What I'd like to know, is if there a way to define a trait like the one

FactoryGirl.define do
  factory :thread do
    trait :with_forum do
      association :user
      # Lazy-evaluate the value of user to the previously created factory
      # THIS IS THE KEY POINT: I want 'user' to be the factory created at the previous line
      association :forum, user: user
    end
  end
end

What the trait is supposed to do is to create an user and associate it to the thread. Then it should create a forum, but the user should be the same instance previously created.

There are mainly two reasons:

  • The user associated with the forum is the same of the thread
  • I don't want to create two user factories on cascade

Any idea? I tried to use the lazy evaluation, but no way to use it with associations.

like image 796
Simone Carletti Avatar asked Oct 20 '22 18:10

Simone Carletti


2 Answers

Does it make sense to do the opposite and set the thread's user to be the same as the forum's? Does the forum factory create a user?

FactoryGirl.define do
  factory :thread do
    trait :with_forum do
      forum
      user { forum.user }
    end
  end
end

If you really want to do it the other way, you can definitely use a lazy attribute:

FactoryGirl.define do
  factory :thread do
    trait :with_forum do
      user
      forum { create(:forum, user: user) }
    end
  end
end

The downside there will be that it will always create a forum regardless of the strategy used to build the thread.

like image 192
Joe Ferris Avatar answered Nov 01 '22 08:11

Joe Ferris


You have to lazily evaluate the association call:

FactoryGirl.define do
  factory :thread do
    trait :with_forum do
      user
      forum { association(:forum, user: user) }
    end
  end
end
like image 32
Joel Crocker Avatar answered Nov 01 '22 10:11

Joel Crocker