Проблема модели ассоциации FactoryGirl: «SystemStackError: слишком большой уровень стека» - PullRequest
10 голосов
/ 20 сентября 2011

Я использую Ruby on Rails 3.0.9, RSpec-rails 2 и FactoryGirl.Я пытаюсь сформулировать модель ассоциации Factory, но у меня проблемы.

У меня есть файл factories/user.rb, подобный следующему:

FactoryGirl.define do
  factory :user, :class => User do
    attribute_1
    attribute_2
    ...

    association :account, :factory => :users_account, :method => :build, :email => 'foo@bar.com'
  end
end

и файл factories/users/account.rb, как показано ниже:

FactoryGirl.define do
  factory :users_account, :class => Users::Account do
    sequence(:email) {|n| "foo#{n}@bar.com" }
    ...
  end
end

Приведенный выше пример работает, как и ожидалось, в моих файлах спецификаций, но , если в операторе factory :users_account, я добавляю код association :user, чтобы

FactoryGirl.define do
  factory :users_account, :class => Users::Account do
    sequence(:email) {|n| "foo#{n}@bar.com" }
    ...
    association      :user
  end
end

Я получаю следующую ошибку:

Failure/Error: Unable to find matching line from backtrace
SystemStackError:
  stack level too deep

Как мне решить эту проблему, чтобы получить доступ к связанным моделям с обеих сторон \ заводов (то есть в моих спецификационных файлах яхотел бы использовать методы модели ассоциации RoR, такие как user.account и account.user) ?

PS: я прочитал вопрос Factory Girl и has_one , и мой случайочень близко к делу, объясненному в связанном вопросеТо есть у меня тоже есть ассоциация has_one (между User и Users::Account классами).

Ответы [ 2 ]

20 голосов
/ 27 декабря 2012

Согласно документам , вы не можете просто поместить обе стороны ассоциаций на фабрики. Вам нужно будет использовать их после обратного вызова, чтобы установить объект (ы) для возврата.

Например, в файле factories/users/account.rb вы помещаете что-то вроде

after(:build) do |user_account, evaluator|
    user_account.user = FactoryGirl.build(:user, :account=>user_account)
end

Для ассоциаций has_many вам необходимо использовать их функции * _list.

after(:build) do |user_account, evaluator|
    user_account.users = FactoryGirl.build_list(:user, 5, :account=>user_account)
end

Примечание: я полагаю, что пример в документации немного вводит в заблуждение, он ничего не назначает объекту. Я считаю, что это должно быть что-то вроде (обратите внимание на задание).

# the after(:create) yields two values; the user instance itself and the
# evaluator, which stores all values from the factory, including ignored
# attributes; `create_list`'s second argument is the number of records
# to create and we make sure the user is associated properly to the post
after(:create) do |user, evaluator|
  user.posts = FactoryGirl.create_list(:post, evaluator.posts_count, user: user)
end
0 голосов
/ 17 февраля 2019

Отличный ответ Spyle (все еще работающий с Rails 5.2 и RSpec 3.8) будет работать для большинства ассоциаций.У меня был случай использования, когда фабрике нужно было использовать 2 разных фабрики (или разные черты) для одной ассоциации has_many (т.е. для метода типа области действия).

В итоге я получил:

# To build user with posts of category == 'Special' and category == 'Regular'
after(:create) do |user, evaluator|
  array = []
  array.push(FactoryBot.create_list(:post, 1, category: 'Regular')
  array.push(FactoryBot.create_list(:post, 1, category: 'Special')
  user.posts = array.flatten
end

Это позволило пользователю иметь 1 пост категории «Обычный» и 1 пост категории «Специальный».

...