2013-04-30 4 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

+2

Я думаю, что ваш пример имеет ошибку. Измените параметр 'after (: create)' to '' profile.user.email = evaluationator.user_email, если только параметр valuator.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. Например. Я получаю предупреждение «DEPRECATION»: «# ignore» устарел и будет удален в версии 5.0 ». при реализации этого ответа. –

+0

У меня уже есть эта проблема в Rails 5 –

+0

Вы можете использовать «переходный» вместо «игнорировать», чтобы избавиться от предупреждения –

3

решаемые его путем создания пользователя, а затем профиля :

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

Итак, это почти то же самое, что и в вопросе, разделенное на две линии. Только реальная разница - это явный доступ к «.id». Протестировано с рельсами 5.

Смежные вопросы