Rails 3 автоматически вставляет данные в соединительную таблицу

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

Разве это не так?

Например, у меня есть модель dvd.rb, которая выглядит так:

  has_and_belongs_to_many :dvd_producer

Таблица соединения называется соответственно dvd_producers_dvds (я знаю, глупое имя, но это то, что ожидает ActiveRecord).

По сути, когда я вставляю нового производителя в таблицу dvd_producers через:

DvdProducer.create(producer: producer)

Я ожидаю, что ActiveRecord автоматически вставит эквивалентные данные (producer_id, dvd_id) в соединительную таблицу.

Может быть, мне нужно использовать метод new_producer.save вместо create?

Или это просто несбыточная мечта?


person kakubei    schedule 15.11.2012    source источник


Ответы (2)


Вы когда-нибудь добавляли DVD в dvd_producer? Я даже не вижу, как вы создаете DVD, что-то вроде.

producer = DvdProducer.create(producer: producer)
producer.dvds << Dvd.create(title: title)

Должен дать вам то, что вы хотите.

person Krustal    schedule 18.11.2012
comment
Не всегда. Иногда мне просто нужно вставить производителя и данные в соединительную таблицу, потому что DVD уже существует. Неужели нет способа сделать это тогда? - person kakubei; 19.11.2012
comment
Что, если у меня есть и другие отношения, такие как режиссер и писатель. Как это можно сделать, как в приведенном выше примере? - person kakubei; 20.11.2012
comment
Хорошо, это работает, если я немного отредактирую. Вместо создания новой записи для dvd я могу сделать dvd.dvd_producer << producer. Я отмечаю ваш пост как ответ, так как он привел меня к правильному случаю. Спасибо - person kakubei; 22.11.2012

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

Итак, чтобы вставить данные в соединительную таблицу для объекта, который у вас уже есть:

dvd = Dvd.find(:id)
producer  = Producer.where(producer: 'some guy').first_or_create
dvd.producer << producer

Конечно, это также работает, если вы создаете объекты, как указано Крусталом выше.

Используйте << для добавления данных в соединительную таблицу и используйте = с объектом в качестве массива для замены данных:

dvd.producer = [producer]

Что хорошо в этом, так это то, что он работает для отношения «многие к одному» (такое, где у вас есть идентификатор в качестве внешнего ключа в другой таблице, например dvd.sound_id), а также с небольшим изменением, используйте = вместо <<:

dvd = Dvd.find(:id)
sound = Sound.where(sound: 'Dolby').first_or_create
dvd.sound = sound

Кроме того, теперь я пристрастился к first_or_create, о существовании которого я даже не подозревал. Это замечательный метод, который избавляет вас от необходимости сначала искать запись и создавать ее, если она не существует. Не могу поверить, что я не знал об этом. Используйте его, это здорово.

person kakubei    schedule 22.11.2012