Предотвращение дублирования только в представлении (Ленивое решение)
Следующее не не предотвращает запись дублирующих связей в базу данных, оно только гарантирует, что find
методы игнорируют дубликаты.
В Rails 5:
has_and_belongs_to_many :tags, -> { distinct }
Примечание: Relation#uniq
устарел в Rails 5 ( commit )
В рельсах 4
has_and_belongs_to_many :tags, -> { uniq }
Предотвращение дублирования данных от сохранения (лучшее решение)
Опция 1: Запрет дублирования с контроллера:
post.tags << tag unless post.tags.include?(tag)
Однако несколько пользователей могут одновременно попытаться post.tags.include?(tag)
, поэтому это зависит от условий гонки. Это обсуждается здесь .
Для надежности вы также можете добавить это к модели Post (post.rb)
def tag=(tag)
tags << tag unless tags.include?(tag)
end
Вариант 2: Создать уникальный индекс
Самый надежный способ предотвращения дублирования - это иметь дублирующие ограничения на уровне базы данных. Этого можно достичь, добавив unique index
к самой таблице.
rails g migration add_index_to_posts
# migration file
add_index :posts_tags, [:post_id, :tag_id], :unique => true
add_index :posts_tags, :tag_id
Если у вас есть уникальный индекс, попытка добавить дублирующую запись вызовет ошибку ActiveRecord::RecordNotUnique
. Обработка этого выходит за рамки этого вопроса. Посмотреть этот ТАК вопрос .
rescue_from ActiveRecord::RecordNotUnique, :with => :some_method