Рейки: використання збірки з асоціацією has_one в рейках


143

У цьому прикладі я створюю userпозначку "ні" profile, потім пізніше створюю profileдля цього користувача. Я спробував використовувати build з 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 асоціацію?


що саме ви спробували? Ви можете, будь ласка, опублікувати якийсь код?
Ju Nogueira

Відповіді:


359

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асоціацію для отримання більш детальної інформації.


28
Різний синтаксис has_one завжди виловлює мене ... чорт!
Галактика

11
Смішно, як найкраща та прийнята відповідь тут відповідає на питання, що відрізняються від того, яке задав ОП.
Ajedi32

Нібито, якщо користувач належав до профілю (тобто таблиця користувача має свою таблицю профілю_id Foreign_key profile_id), тоді також створення профілю для користувача буде працювати, як було зазначено вище, тобто, але для нових дій лише user.build_profile для редагування, user.build_profile if user.profile.nil? і якщо ви хочете створити профіль під час створення користувача, напишіть accepts_nested_attributes_for :profileце в Модель користувача. і у формі, який створюється користувачем, напишіть <%= f.simple_fields_for :profile do |p| %>це і продовжуйте.
завзяття

але чому така інша поведінка зберігалася для has_one або has_many? Була б якась причина при проектуванні, я думаю, і очікую.
допитливий

@ Ajedi32 відповідь відповідає заголовку питання, але не тілу. Зважаючи на те, що це ( build_<association>) є досить дивною та несподіваною поведінкою в Rails, є набагато більше людей, які шукають цю відповідь, ніж відповіді на фактичні запитання, якщо ви знаєте, що я маю на увазі.
Макс Вільямс

19

Погляньте добре на повідомлення про помилку. Це говорить про те, що user_idу таблиці профілів у вас немає необхідного стовпця . Встановлення взаємозв'язків у моделі - лише частина відповіді.

Також потрібно створити міграцію, яка додає user_idстовпець до таблиці профілів. Rails очікує, що це буде там, і якщо його немає, ви не можете отримати доступ до профілю.

Для отримання додаткової інформації перегляньте це посилання:

Основи асоціації


1
Я просто з'ясував свою проблему. Книга, з якої я навчаюсь, не дуже добре пояснила створення іноземних ключів. Я створив нову міграцію, яка додає зовнішній ключ до моєї моделі. Дякую.
espinet

Чи потрібно щоразу створювати стовпчик самостійно? У мене була така ідея, що це сталося автоматично. Я не знаю, звідки у мене така ідея.
Ріміан

Ви можете додати стовпчик під час генерації моделі за допомогою командного рядка rails g model profile user:references:index address:string bio:text.
duykhoa

1

Залежно від випадку використання, може бути зручно обернути метод і автоматично побудувати об'єднання, коли його не знайдено.

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

тепер виклик #profileметоду поверне пов'язаний профіль або створить новий екземпляр.

Джерело: Коли мавпа виправляє метод, ви можете викликати перезаписаний метод з нової реалізації?


1
в поточних рейках (перевірено на 6.0.2.2) , ви можете спростити це: def profile; super || build_profile; end.
glasz

-14

Це має бути а has_one. Якщо buildце не працює, ви можете просто скористатися new:

ModelName.new( :owner => @owner )

те саме, що

@owner.model_names.build

11
Це не те саме: якщо ви створили нове ім’я моделі з збіркою, коли @owner збережено, нове ім'я моделі також буде збережено. Таким чином, ви можете використовувати build для створення батька та дітей, які будуть збережені разом. Це не так, якщо ви робите ім'я моделі з .new
Макс Вільямс,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.