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

Провел весь день в Google, но не нашел ответа.:\

У меня есть связь HABTM между пользователями и Core_Values.

class CoreValue < ActiveRecord::Base
  has_and_belongs_to_many :users

class User < ActiveRecord::Base
  has_and_belongs_to_many :core_values

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

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

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

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

Это создает новый CoreValue с: значением и: created_by и создает ассоциацию.

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

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

Ответы

Ответ 1

Вы можете сделать это в двухэтапной процедуре, используя очень полезный метод 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)

Ответ 2

Добавьте метод в свою модель пользователя:

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. Связывает основное значение (созданное/найденное) с пользователем.

Ответ 3

Активная запись уже дает вам метод. В вашем случае

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

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

Отметьте этот для получения дополнительной информации