Before we begin. A helpful note is to set config.use_transactional_fixtures = true
in your spec helper. I found that when I wasn’t doing this, Factory Girl was creating duplicate instances of my models and because of that, validations were failing.
So recently at work I’ve been refactoring the user models into polymorphic associations. Part of that process was introducing new factories for these polymorphic associations in Factory Girl. The associations are as follows:
class Profile
belongs_to :profileable, polymorphic: true
end
class Account
belongs_to :accountable, polymorphic: true
end
class Student
has_one :profile, as: :profileable
has_one :account, as: :accountable
end
class Teacher
has_one :profile, as: :profileable
has_one :account, as: :accountable
end
Breaking down the models this way allows us to seperate the concerns of authentication, profile information and teacher/student specific information into their own datasets. I favour this over STI because here, there are no nil
columns anywhere.
So the question remains, how do we create factories for such associations? Well first we need to create a profile and account factory and specify them as polymorphic:
FactoryGirl.define do
factory :account, class: Account do
email { Faker::Internet.email }
password { "supersecret" }
password_confirmation { "supersecret" }
association :accountable
end
end
FactoryGirl.define do
factory :account, class: Account do
first_name { Faker::Name.first_name }
last_name { Faker::Name.last_name }
association :profileable
end
end
We associate the factories to their polymorphicable (is that a word?), because in the model, they belong to their polymorphicable. Now it’s time to create the student and teacher factories:
FactoryGirl.define do
factory :student, class: Student do
trait :trial { subscription_status: 0 }
trait :subscribed { subscription_status: 1 }
after(:create) do |student|
create(:account, accountable: student)
create(:profile, profileable: student)
end
end
end
For the sake of scrolling, I won’t create the teacher factory because it’s the same idea. 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.
TADA. Polymorphic associations in FactoryGirl… Done!