Использование сборки с ассоциацией has_one в рельсах

В этом примере я создаю user без profile, а затем создаю profile для этого пользователя. Я попытался использовать сборку с ассоциацией has_one, но это взорвалось. Единственный способ, с помощью которого я вижу эту работу, - использовать has_many. Предполагается, что user имеет не более одного profile.

Я пытался это сделать. У меня есть:

class User < ActiveRecord::Base
  has_one :profile
end

class Profile < ActiveRecord::Base
  belongs_to :user
end

Но когда я это делаю:

user.build_profile 

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

ActiveRecord::StatementInvalid: Mysql::Error: Unknown column 'profiles.user_id' in 'where clause': SELECT * FROM `profiles` WHERE (`profiles`.user_id = 4)  LIMIT 1

Есть ли способ в рельсах иметь 0 или 1 ассоциацию?

Ответ 1

Подпись build отличается для ассоциаций has_one и has_many.

class User < ActiveRecord::Base
  has_one :profile
  has_many :messages
end

Синтаксис сборки для ассоциации has_many:

user.messages.build

Синтаксис сборки для ассоциации has_one:

user.build_profile  # this will work

user.profile.build  # this will throw error

Подробнее читайте has_one ассоциацию .

Ответ 2

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

Вам также необходимо создать перенос, который добавляет столбец user_id в таблицу профилей. Rails ожидает, что это будет там, и если это не так, вы не сможете получить доступ к профилю.

Для получения дополнительной информации перейдите по этой ссылке:

Основы ассоциации

Ответ 3

В зависимости от варианта использования может быть удобно обернуть метод и автоматически построить ассоциацию, если он не найден.

old_profile = instance_method(:profile)
define_method(:profile) do
  old_profile.bind(self).call || build_profile
end

теперь вызов метода #profile приведет либо к возврату связанного профиля, либо к созданию нового экземпляра.

Источник: Когда обезьяна исправляет метод, вы можете вызвать переопределенный метод из новой реализации?

Ответ 4

Он должен быть has_one. Если build не работает, вы можете просто использовать new:

ModelName.new( :owner => @owner )

совпадает с

@owner.model_names.build