2013-04-30 8 views
22

これはおそらく愚かですが、どこにでもサンプルが見つかりません。FactoryGirlは関連付けられたオブジェクトの属性をオーバーライドします

私は2つの工場があります。

p = FactoryGirl.create(:profile, user: {email: "[email protected]"}) 

または類似した何かが、私はできません:私は何をしたいか

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 

は、私は、プロファイルを作成するときに、ユーザーのいくつかの属性をオーバーライドしています構文を正しく取得します。エラー:

ActiveRecord::AssociationTypeMismatch: User(#70239688060520) expected, got Hash(#70239631338900) 

私は私が最初にユーザーを作成し、プロファイルに関連付けることで、これを行うことができます知っているが、私はより良い方法がなければならないと思いました。

それともこれは動作します:

p = FactoryGirl.create(:profile, user: FactoryGirl.create(:user, email: "[email protected]")) 

が、これは過度に複雑なようです。関連する属性をオーバーライドする簡単な方法はありませんか? これの正しい構文は何ですか?

答えて

6

私はあなたがコールバックと一時的な属性でこの仕事をすることができると思います。あなたはそのようなあなたのプロフィール工場を変更する場合:

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 

は、あなたが希望する結果をこのようにそれを起動して得ることができる必要があります:私は、それをテストしていません

p = FactoryGirl.create(:profile, user_email: "[email protected]") 

+0

ありがとうございましたが、私はそれをすべての属性で動作させたいと思っています。たぶん誰もこれを必要としない... – bobomoreno

+2

あなたの例にはエラーがあると思う。 'after(:create)'を 'profile.user.email = evaluator.user_email 'に変更してください.evaluator.user_email.nil?' – Kelly

18

FactoryGirlの作成者の一人によると、動的引数をアソシエーションヘルパー(Pass parameter in setting attribute on association in FactoryGirl)に渡すことはできません。

しかし、あなたはこのような何かを行うことができるはず:

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 

次に、あなたが望んでいたほとんどのようにそれを呼び出すことができます。

p = FactoryGirl.create(:profile, user_args: {email: "[email protected]"}) 
+2

偉大な答えです。最新のRailsバージョンに準拠するようにこれを更新しますか?例えば。私は '' DEPRECTION WARNING: '#ignore'は廃止され、5.0で削除されるでしょう。"この回答を実装するとき –

+0

私は既にこの問題をRails 5に持っています –

+0

警告を取り除くために "無視"の代わりに "transient"を使うことができます –

3

は、最初にユーザーを作成することによってそれを解決した後、プロフィール:

my_user = FactoryGirl.create(:user, user_email: "[email protected]") 
my_profile = FactoryGirl.create(:profile, user: my_user.id) 

これは、2行にまたがる質問とほぼ同じです。 実際の違いは ".id"への明示的なアクセスだけです。 Rails 5でテストしました。

関連する問題