Rails: имеет и принадлежит многим (HABTM) - создайте ассоциацию без создания других записей - PullRequest
15 голосов
/ 19 января 2011

Провел весь день в Google, но не могу найти ответ.: \

У меня есть отношения HABTM между Users и Core_Values.

class CoreValue < ActiveRecord::Base
  has_and_belongs_to_many :users

class User < ActiveRecord::Base
  has_and_belongs_to_many :core_values

В моем контроллере мне нужно сделать две разные вещи:

  1. ЕслиCoreValue не существует, создайте новый и свяжите его с данным идентификатором пользователя, и
  2. Если я знаю, что конкретное CoreValue уже существует, создайте ассоциацию без создания каких-либо новых CoreValues ​​или Users

Для # 1 у меня это работает:

User.find(current_user.id).core_values.create({:value => v, :created_by => current_user.id})

Это создает новое CoreValue с: value и: creation_by и создает связь.

Для # 2Я пробовал несколько вещей, но не могу создать ассоциацию ТОЛЬКО.

Спасибо за вашу помощь!

Ответы [ 3 ]

21 голосов
/ 19 января 2011

Вы можете сделать это в два этапа, используя очень полезный метод find_or_create.find_or_create сначала попытается найти запись, и, если она не существует, создайте ее.Примерно так должно быть:

core_value = CoreValue.find_or_create_by_value(v, :created_by => current_user.id)
current_user.core_values << core_value

Некоторые примечания:

  • В первой строке будет найдено или создано значение v.Если он не существует и создан, он установит created_by в current_user.id.
  • Нет необходимости делать User.find(current_user.id), так как это вернет тот же объект, что и current_user.
  • current_user.core_values - это массив, и вы можете легко добавить к нему другое значение, используя <<.

Для краткости следующее будет таким же, как в примере кода выше:

current_user.core_values << CoreValue.find_or_create_by_value(v, :created_by => current_user.id)
4 голосов
/ 19 января 2011

Добавьте метод в вашей пользовательской модели:

class User < ActiveRecord::Base
  def assign_core_value(v)
    core_values.find_by_name(v) || ( self.core_values << 
      CoreValue.find_or_create_by_name(:name => v, :created_by => self)).last 
  end
end

Метод assign_core_value отвечает требованию 1,2 и возвращает значение ядра, назначенное пользователю (с заданным именем).

Теперь вы можете сделать следующее:

current_user.assign_core_value(v)

Примечание 1

Метод логики выглядит следующим образом:

1) Проверяет, связано ли CoreValue с пользователем. Если так, никаких действий не предпринимается, возвращается значение ядра.

2) Проверяет, существует ли CoreValue с указанным именем. Если не создает CoreValue. Связывает значение ядра (создано / найдено) с пользователем.

0 голосов
/ 06 июня 2012

Active Record уже дает вам метод.В вашем случае,

val = CoreValue.find_by_value(v)
current_user.core_values << val

Вы также можете передать несколько объектов таким образом.Будут созданы все ассоциации

. Проверьте , это , для получения дополнительной информации

.
...