I currently have a FactoryBot trait set up as follows:
trait :with_role do
transient do
role { nil }
end
after(:create) do |staff_member, factory|
staff_member.staff_roles << StaffRole.fetch(factory.role) if factory.role
end
end
However, this trait only allows the factory to be passed a single role. I'm refactoring a series of tests wherein mutliple roles need to be assigned. This is a M-N relationship supported both by the DB and ORM via a junction table, and clearly functions as expected outside of FactoryBot because the original test implementation passes. My approach is as follows:
# Inside the factory
trait :with_roles do
transient do
roles { [] }
end
after(:create) do |staff_member, factory|
roles.each { |role| staff_member.staff_roles << StaffRole.fetch(factory.send(role)) }
end
end
# Invocation
staff_member = FactoryBot.create(:staff_member, :with_roles, roles: [
:role_1,
:role_2,
:role_3
], some_other_attribute: 1)
The problem is that when I try to invoke in this way, I get the following error:
NameError: undefined local variable or method `roles' for #<FactoryBot::SyntaxRunner:...>
I get the exact same error if I initialise roles
as nil
instead of an empty array. The previous implementation works fine, and I've followed it as closely as possible. Why is roles
undefined despite being defined as a transient variable? Am I missing something about how FactoryBot works, and trying to do something impossible? Or am I just appproaching this wrong?
CodePudding user response:
You should call a transient attribute on a factory:
after(:create) do |staff_member, factory|
factory.roles.each { |role| staff_member.staff_roles << StaffRole.fetch(factory.send(role)) }
end