I have an Account model that has_one User model, and a User model that belongs_to Account model. I think that the basic code required for demonstration is:
class Account < ActiveRecord::Base
has_one :user
validates_presence_of :user
accepts_nested_attributes_for :user
end
class User < ActiveRecord::Base
belongs_to :account
# validates_presence_of :account # this is not actually present,
# but is implied by a not null requirement
# in the database, so it only takes effect on
# save or update, instead of on #valid?
end
When I define associations in each factory:
Factory.define :user do |f|
f.association :account
end
Factory.define :account do |f|
f.association :user
end
I get a stack overflow, as each is creating an account/user recursively.
The way I've been able to solve this is to emulate nested attribute forms in my tests:
before :each do
account_attributes = Factory.attributes_for :account
account_attributes[:user_attributes] = Factory.attributes_for :user
@account = Account.new(account_attributes)
end
However, I'd like to keep this logic in the factory, as it can get out of hand once I start adding other modules:
before :each do
account_attributes = Factory.attributes_for :account
account_attributes[:user_attributes] = Factory.attributes_for :user
account_attributes[:user_attributes][:profile_attributes] = Factory.attributes_for :profile
account_attributes[:payment_profile_attributes] = Factory.attributes_for :payment_profile
account_attributes[:subscription_attributes] = Factory.attributes_for :subscription
@account = Account.new(account_attributes)
end
Please help!
I was able to solve this problem by using factory_girl's after_build callback.
Factory.define :account do |f|
f.after_build do |account|
account.user ||= Factory.build(:user, :account => account)
account.payment_profile ||= Factory.build(:payment_profile, :account => account)
account.subscription ||= Factory.build(:subscription, :account => account)
end
end
Factory.define :user do |f|
f.after_build do |user|
user.account ||= Factory.build(:account, :user => user)
user.profile ||= Factory.build(:profile, :user => user)
end
end
This will create the associated classes before the owning class is saved, so validations pass.
Have a look at the factory_girl documentation. The way you're building those accounts seems like you're not really taking advantage of factory_girl.
I've always taken care of associations by creating the objects that I need before testing. I'm going to take a stab at this based on the models you're referencing above:
before :each do
@account = Factory(:account, :user_id => Factory(:user).id, :profile_id => Factory(:profile).id)
end
Now @account
will have @account.user
and @account.profile
available. If you need to define those, @profile = @account.profile
works just great.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With