Подтвердить что ты не робот

Атрибут 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]"))

но это кажется слишком сложным. Нет ли более простого способа переопределить связанный атрибут? Каков правильный синтаксис для этого?

4b9b3361

Ответ 1

По словам одного из создателей FactoryGirl, вы не можете передавать динамические аргументы помощнику ассоциации (параметр Pass в атрибуте настройки при ассоциации в 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

Я думаю, вы можете сделать эту работу с обратными вызовами и переходными атрибутами. Если вы измените свой профиль factory следующим образом:

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]")

Я еще не тестировал его.

Ответ 3

Решил его, сначала создав User, а затем Profile:

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

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