问题
This is probably silly simple but I can't find an example anywhere.
I have two factories:
FactoryGirl.define do
factory :profile do
user
title "director"
bio "I am very good at things"
linked_in "http://my.linkedin.profile.com"
website "www.mysite.com"
city "London"
end
end
FactoryGirl.define do
factory :user do |u|
u.first_name {Faker::Name.first_name}
u.last_name {Faker::Name.last_name}
company 'National Stock Exchange'
u.email {Faker::Internet.email}
end
end
What I want to do is override some of the user attributes when I create a profile:
p = FactoryGirl.create(:profile, user: {email: "test@test.com"})
or something similar, but I can't get the syntax right. Error:
ActiveRecord::AssociationTypeMismatch: User(#70239688060520) expected, got Hash(#70239631338900)
I know I can do this by creating the user first and then associating it with the profile, but I thought there must be a better way.
Or this will work:
p = FactoryGirl.create(:profile, user: FactoryGirl.create(:user, email: "test@test.com"))
but this seems overly complex. Is there not a simpler way to override an associated attribute? What is the correct syntax for this??
回答1:
According to one of FactoryGirl's creators, you can't pass dynamic arguments to the association helper (Pass parameter in setting attribute on association in FactoryGirl).
However, you should be able to do something like this:
FactoryGirl.define do
factory :profile do
transient do
user_args nil
end
user { build(:user, user_args) }
after(:create) do |profile|
profile.user.save!
end
end
end
Then you can call it almost like you wanted:
p = FactoryGirl.create(:profile, user_args: {email: "test@test.com"})
回答2:
I think you can make this work with callbacks and transient attributes. If you modify your profile factory like so:
FactoryGirl.define do
factory :profile do
user
ignore do
user_email nil # by default, we'll use the value from the user factory
end
title "director"
bio "I am very good at things"
linked_in "http://my.linkedin.profile.com"
website "www.mysite.com"
city "London"
after(:create) do |profile, evaluator|
# update the user email if we specified a value in the invocation
profile.user.email = evaluator.user_email unless evaluator.user_email.nil?
end
end
end
then you should be able to invoke it like this and get the desired result:
p = FactoryGirl.create(:profile, user_email: "test@test.com")
I haven't tested it, though.
回答3:
Solved it by creating User first, and then Profile:
my_user = FactoryGirl.create(:user, user_email: "test@test.com")
my_profile = FactoryGirl.create(:profile, user: my_user.id)
So, this is almost the same as in the question, split across two lines. Only real difference is the explicit access to ".id". Tested with Rails 5.
来源:https://stackoverflow.com/questions/16297357/factorygirl-override-attribute-of-associated-object