eeeeeean eeeeeean - 6 months ago 25
Ruby Question

Using a transient attribute in before(:create) callback

I'm new to factory girl. I want to create a Share factory that belongs to both a Membership and a Stake factory (so that both have an association with the same Group instance). I'm trying to write my Share factory as follows instead of using the association method to avoid callbacks that would create the Share.

factory :share do
transient do
same_group
end

before(:create) do |share, evaluator|
stake = create(:shareless_stake, group: evaluator.same_group)
member = create(:shareless_membership, group: evaluator.same_group)
share.stake = stake
share.membership = member
end
end


Then I want to create the Share like this:

share = create(:share, same_group: create(:group))


I'm getting an error saying that the 'same_group' trait is not registered. When I create a trait, or create a factory under the Group factory by that name, it complains that there is no 'group=' setter method for the built instance of Share.

I'm confused as it looks like factory_girl is trying to treat my transient attribute as an actual attribute of Share, which I don't want. I just want same_group to be a variable for a Group instance that I can pass along to the before(:create) block. What am I doing wrong?

Answer

Defining same_group without a default value causes Factory Girl to treat it as an association rather than an attribute (and attempt to look up a factory of the same name). Changing this line to e.g. same_group nil would solve that problem. It's an admittedly confusing aspect of Factory Girl that the same method can be treated as either an attribute or an association depending on the number of arguments or presence of a block.