Consider this factory:
# Read about factories at http://github.com/thoughtbot/factory_girl
FactoryGirl.define do
factory :follow_up do
first_name { Faker::Name.first_name }
last_name { Faker::Name.last_name }
phone { Faker::PhoneNumber.cell_phone.gsub(/[^\d]/, '').gsub(/^1/, '2')[0..9] }
email { Faker::Internet.email }
email_preferred true
consent false
trait :by_referral do
association :hospital
association :referral
source { FollowUp::REFERRAL}
end
trait :by_provider do
association :provider
source { FollowUp::PROVIDER }
end
end
end
I want to either default to include the by_referral trait, or the by_provider trait. It shouldn't be valid if neither trait is included. Is this possible, or is there a better way to do this?
There's no direct way to shut off a factory or force a trait to be included, but what about something like this?
trait :follow_up_defaults do
first_name {}
last_name {}
# ...
end
factory :follow_up_from_referral, class: FollowUp do
follow_up_defaults
hospital
referral
source { FollowUp::REFERRAL }
end
factory :follow_up_from_provider, class: FollowUp do
follow_up_defaults
provider
source { FollowUp::PROVIDER }
end
The other way would be to include a trait in a factory by default:
factory :follow_up do
first_name {}
last_name {}
# ...
by_referral # <== defaults to by_referral
trait :by_referral do
# ...
end
trait :by_provider do
# ...
end
The potential issue here is that the association from the base trait will always be included, even if it technically shouldn't be. The first solution (while feeling a bit weird) ensures that a follow up always falls into one of the two categories.
Let me know if anything's not clear or if you come up with any more ideas for how to solve this!
Turns out I can chuck an if statement into a factory, so this works:
# Read about factories at http://github.com/thoughtbot/factory_girl
FactoryGirl.define do
factory :follow_up do
first_name { Faker::Name.first_name }
last_name { Faker::Name.last_name }
phone { Faker::PhoneNumber.cell_phone.gsub(/[^\d]/, '').gsub(/^1/, '2')[0..9] }
email { Faker::Internet.email }
email_preferred true
consent false
if [1, 2].sample == 1
by_referral
else
by_provider
end
trait :by_referral do
association :hospital
association :referral
source { FollowUp::REFERRAL}
end
trait :by_provider do
association :provider
source { FollowUp::PROVIDER }
end
end
end
Thanks @joshuaclayton
In case anybody else comes across the same issue as me - you cannot have a default trait which has the same name as an existing factory. See https://github.com/alphagov/content-publisher/pull/1568#discussion_r362202799 for full context.
Instead of
image
trait :image do
# etc
end
...I had to rename to:
for_image
trait :for_image do
# etc
end
...as I already had an :image
factory elsewhere in the repository.
This nuance is captured in the getting started guide: "Note that defining traits as implicit attributes will not work if you have a factory or sequence with the same name as the trait" - but is easy to miss if you are skimming.
Most helpful comment
There's no direct way to shut off a factory or force a trait to be included, but what about something like this?
The other way would be to include a trait in a factory by default:
The potential issue here is that the association from the base trait will always be included, even if it technically shouldn't be. The first solution (while feeling a bit weird) ensures that a follow up always falls into one of the two categories.
Let me know if anything's not clear or if you come up with any more ideas for how to solve this!