Обновление ассоциации вновь созданного объекта внутри его блока - PullRequest
0 голосов
/ 30 сентября 2018

Rails 5.2.1

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

has_one :profile
before_create :build_profile

Это работает, когда пользователь регистрируется на моем сайте, создавая связанный объект профиля.

Использование seed.rd и внутри:

require 'faker'

User.create(email: Faker::Internet.email, password: 'nopassword') do |u|
  u.profile.update_attributes({...})
  # u.create_profile({...}) ActiveRecord::RecordNotSaved: You cannot call create unless the parent is saved
end

NoMethodError: неопределенный метод update_attributes для nil: NilClass

ActiveRecord не вызывается всемена.рб?Что работает?:

[...]

u.build_profile({...})

[...]

Проблема с этим теперь в том, что у меня дублирующиеся объекты из-за before_create :build_profile.Удалив эту строку из файла user.rb, все хорошо.Мне не нужно удалять его, и я по-прежнему могу запустить файл seed.rb без проблем.Как этого добиться?

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

Это потому, что блок для создания вызывается перед сохранением вашего объекта.Это означает, что ваш обратный вызов еще не сработал, когда ваш блок выполняется, вы можете легко проверить его с помощью:

User.create { |u| puts u.persisted? }

Чтобы заставить его работать с вами с блоком, вы можете использовать tap:

User.create.tap { |u| u.profile.update_attributes }
0 голосов
/ 30 сентября 2018

А что если вы обновите профиль после создания пользователя?

u = User.create(...)
u.profile.update_attributes({...})

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

Если вы вызовете profile.update_attributes внутри блока, он создаст профиль до того, как before_create запустится, а затем before_create создаст еще один.

Если вы действительно хотите использовать блок, вы можете проверить в своем методе before_create, который будет создавать профиль, только если он еще не существует:

before_create :ensure_profile_built

private
def ensure_profile_built
  build_profile unless profile
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...