Как проверить уникальный набор ассоциаций «многие ко многим»? - PullRequest
0 голосов
/ 02 января 2019

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

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

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

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

class Exercise < ApplicationRecord
  has_many :exercise_elements, dependent: :destroy
  has_many :elements, through: :exercise_elements
  accepts_nested_attributes_for :exercise_elements, allow_destroy: true
  validate :element_uniqueness, if: :elements_unique?, on: :update

  def elements_unique?
    all_exercises_but_self = Exercise.where.not(id: self.id)
    all_exercises = all_exercises_but_self.map(&:elements)
    all_sorted = all_exercises.each.sort
    this_exercise = self.elements.sort
    all_sorted.include?(this_exercise) ? true : false
  end

  def element_uniqueness
    if elements_unique?
      self.errors[:base] << "Exercise already exists, consider adding 
      different elements"
    end
  end
end

class ExerciseElement < ApplicationRecord
  belongs_to :exercise
  belongs_to :element
end

class Element < ApplicationRecord
  belongs_to :element_category
  has_many :exercise_elements
  has_many :exercises, through: :exercise_elements
end

Я бы ожидал

exercise1 = Exercise.create
exercise1.elements.push([Element.find(1), Element.find(2)])
exercise1.valid? > true

exercise2 = Exercise.create
exercise2.elements << Element.find(2)
exercise2.valid? > true
exercise2.elements << Element.find(1)
exercise2.valid? > false # invalid because associated elements are not a 
                         # unique set
                         # because exercise2.elements == exercise1.elements
...