2013-04-30 186 views
22

這可能很簡單,但我無法在任何地方找到示例。FactoryGirl覆蓋關聯對象的屬性

我有兩個工廠:

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 

我想要做的是覆蓋某些用戶,當我創建一個配置文件屬性:

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

或類似的東西,但我不能獲得正確的語法。錯誤:

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 2013-05-01 11:44:47

+2

我認爲你的例子有一個錯誤。將'after(:create)'改爲'profile.user.email = evaluateator.user_email,除非evaluateator.user_email.nil?' – Kelly 2015-10-23 21:45:52

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版本。例如。我收到了「拒絕警告:'#ignore'已棄用,並將在5.0中刪除。」當實現這個答案。 – 2016-02-02 00:46:52

+0

我已經有這個問題在Rails 5中 – 2016-06-24 16:46:19

+0

你可以使用「transient」而不是「ignore」來擺脫警告 – 2016-07-18 13:25:47

3

先建立用戶解決了它,然後檔案:

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

所以,這幾乎與問題中的相同,分爲兩行。 唯一真正的區別是對「.id」的顯式訪問。 用Rails 5測試過。