Как загрузить фикстуры в определенном порядке в Rails 5

У меня есть две взаимозависимые модели: учетная запись и пользователь. Учетная запись всегда создается пользователем, чей идентификатор таким образом хранится в атрибуте Creator_id учетной записи, и пользователь обязательно принадлежит учетной записи (но нет ограничений на количество пользователей, принадлежащих учетной записи), эта информация хранится в учетной записи пользователя. атрибут account_id. Один и тот же пользователь может создать разные учетные записи.

Я сформулировал эти правила так:

Модель пользователя:

belongs_to :account, inverse_of: :users
has_many :created_accounts, class_name: "Account", :foreign_key => "creator_id"

Модель аккаунта:

 belongs_to :creator, class_name: 'User', optional: true
 has_many :users, inverse_of: :account

Поскольку они взаимозависимы, я использовал грязный обходной путь, чтобы создать их экземпляры: сначала я создаю учетную запись, а после этого действия я заставляю пользователя создать свой профиль, и его user_id добавляется в учетную запись как Creator_id в обновлении.

Вот почему у меня в модели учетной записи:

validate :require_actual_creator_id, on: :update
------------------------------------------------
 def require_actual_creator_id
    User.find(creator_id)
  end

Я работал над системой аутентификации, включающей только пользовательскую модель, поэтому я закомментировал эти строки до вчерашнего дня, когда раскомментировал их.

Я запустил db:migrate:reset, db:seed и db:migrate RAILS_ENV=test без каких-либо проблем, обе модели ведут себя нормально в консоли, но когда дело доходит до фикстур (например, тестирование или db:fixtures:load), я получил следующую ошибку:

NoMethodError: undefined method `id' for nil:NilClass
/home/vincent/workspace/bam-rails/test/fixtures/users.yml:16:in `get_binding'

Вот одно типичное приспособление, вызывающее проблему, строка 16 является закомментированной:

michael:
  id: 1
  handle: Michael Example
  email: [email protected]
  encrypted_password: <%= User.generate_encrypted_token('password') %>
  role_id: <%= User::ADMIN %>
  is_activated: true
  activated_at: <%= DateTime.now %>
  #account_id: <%#= Account.first.id %>

Когда я прокомментирую эту последнюю строку, проблем больше не будет. Однако я хотел бы загрузить правильные приборы для своих тестов, потому что, например, созданный здесь пользователь недействителен.

Я прочитал в этот пост, что фикстуры загружаются в алфавитном порядке. Если это так, я не могу понять, почему я должен комментировать эту строку, потому что учетные записи должны загружаться перед пользователями.

Я обнаружил, что это решение работает, но оно не от официального документация, и она довольно старая, датированная 2007 годом. Я боюсь, что это перестанет работать со дня на день.

Кто-нибудь знает, как правильно загружать фикстуры в произвольном порядке в Rails 5, или есть другое решение моей проблемы? Заранее спасибо.


person V. Déhaye    schedule 18.10.2016    source источник


Ответы (1)


Проблема, с которой вы столкнулись, полностью связана с тем, как вы организовали свой код. Проблема заключается в том, что вы создаете первую учетную запись. Таким образом, тот факт, что к моменту создания экземпляра вашего пользователя ваша учетная запись еще не существует, потому что приборы еще не загружены; об этом, я уверен, вы знаете. Фикстуры общеизвестно хрупкие, поэтому люди часто отказываются от них по мере того, как становится сложнее их код. В этом случае, несмотря на то, что они помогают вам выявить запах кода, каждый раз, когда заказ или запуск вашего теста или базовая настройка, не относящаяся к тестовому сценарию, вызывает проблемы, это означает, что у вас есть проблема с вашим кодом. Я бы посоветовал вам найти способ, используя эту «грязную работу».

Теперь, если по какой-то причине вы женаты на том, как ваш код в настоящее время организован, я предлагаю, возможно, переключиться на фабричная девушка , это даст вам немного больше гибкости для управления точкой, в которой создаются экземпляры ваших фиктивных объектов, таким образом, вы не столкнетесь с этой проблемой. Однако я скажу, что это просто позволит вам продолжить этот путь, который, скорее всего, просто приведет к большему количеству проблем в будущем, лучше всего повторно реализовать эту функцию.

person C dot StrifeVII    schedule 18.10.2016
comment
Спасибо за ваш ответ. Factor girl кажется удобным, я могу использовать его в будущем. О том, как устроен мой код, к сожалению, я не могу его изменить, потому что это не я решаю. Однако я нашел решение своей точной проблемы, которая заключалась не в том, чтобы генерировать идентификатор с помощью erb и User.first.id, а просто писать его в виде простого текста, например «1». Таким образом, вы не можете быть уверены, что это настоящий идентификатор, и объект может быть недействительным, но, по крайней мере, идентификатор есть, и если вы аккуратно управляете своими приборами, он соответствует реальной записи. - person V. Déhaye; 18.10.2016
comment
Просто имейте в виду, что я работал над кодовой базой, которая основывалась на определенных записях, находящихся в базе данных, что буквально приводило к кошмарам. Вы хотите стремиться к тому, чтобы ваш код был как можно более апатридным, но я рад, что вы выбрались из грязи. - person C dot StrifeVII; 18.10.2016