Factory Girl: How to associate a record to another record without creating a new record?
I'm using Factory Girl/Rspec2/Rails 3.
In factories.rb, I have:
Factory.define :user do |user|
user.name 'Some guy'
user.email 'some_guy@somewhere.org'
user.password 'password'
end
Factory.define :org_admin, :parent => :user do |user|
user.email 'org_admin@somehwere.org'
end
Factory.define :user_with_membership_request, :parent => :user do |user|
user.email 'user_with_membership_request@somehwere.org'
end
Factory.define :organization do |org|
org.name 'MEC'
org.description 'Mo开发者_开发技巧untain Equipment Co-op'
end
Factory.define :membership do |membership|
membership.user { Factory(:user) }
membership.organization { Factory(:organization) }
end
Factory.define :admin_membership, :parent => :membership do |membership|
membership.user { Factory(:org_admin) }
membership.is_admin true
membership.status 'active'
end
Factory.define :membership_request, :parent => :membership do |membership|
membership.user { Factory(:user_with_membership_request) }
membership.status 'requested'
end
and then in my rspec test I have:
it 'should accept the membership request' do
@org_admin = Factory(:org_admin)
test_sign_in(@org_admin)
@organization = Factory(:organization)
@membership_request = Factory(:membership_request)
put :update, :organization_id => @organization.id, :id => @membership_request.id, :acceptance => 'approve'
...
end
When I run the test, I get:
Failure/Error: @membership_request = Factory(:membership_request)
Validation failed: Name has already been taken
I understand the reason for the failure is because FactoryGirl is creating another organization (with the same name).
But what I'd like to do is create several memberships all associated with the same organization. How do I do that?
Thanks.
Sean
You could check for an existing organization and use it, or create one if none exists:
Factory.define :membership do |membership|
membership.user { Factory(:user) }
membership.organization { Organization.first || Factory(:organization) }
end
FactoryGirl 4+ update:
Factory.define do
factory :membership do
user { create(:user) }
organization { Organization.first || create(:organization) }
end
end
Another approach is to use unique identifiers (e.g.: names) for each factory that you want to reuse, then use initialize_with
to generate it:
factory :organization_1 do
ignore { organization_name 'Sample Organization 1' }
name { organization_name }
initialize_with { Organization.find_or_create_by_name(organization_name) }
end
Now any reference to :organization_1
will always retrieve the same Organization
. Obviously, you must use distinct names for this to work.
There are two things.
1. You might still want to create unique names for Factory(:organisation)
you can achieve that using Factory.sequence
which will generate it uniquely for you.
2. You can pass in a Factory(:membership_request, :organization => @organization)
to use the existing object instead of creating a new one.
With mongoid you can take combine the use of the #find_or_create_by method with Factory.attributes_for and do something like this
factory :membership do
organization { Organization.find_or_create_by(Factory.attributes_for(:organization))}
end
I'm sure ActiveRecord has something similar.
精彩评论