очень трудно рекомендовать "правильный" подход.
1) Прагматичный подход
Используйте валидатор и не добавляйте уникальный составной индекс. Это дает вам хорошие сообщения в пользовательском интерфейсе, и это просто работает.
class CategoryPost < ActiveRecord::Base
belongs_to :category
belongs_to :post
validates_uniqueness_of :category_id, :scope => :post_id, :message => "can only have one post assigned"
end
Вы также можете добавить два отдельных индекса в таблицы объединения для ускорения поиска:
add_index :categories_posts, :category_id
add_index :categories_posts, :post_id
Обратите внимание (согласно книге Rails 3 Way ) проверка не является надежной из-за возможного состязания между запросами SELECT и INSERT / UPDATE . Рекомендуется использовать уникальное ограничение, если вы абсолютно уверены, что нет повторяющихся записей.
2) Пуленепробиваемый подход
В этом подходе мы хотим наложить ограничение на уровень базы данных. Так что это означает создание составного индекса:
add_index :categories_posts, [ :category_id, :post_id ], :unique => true, :name => 'by_category_and_post'
Большим преимуществом является большая целостность базы данных, недостатком является не столько полезное сообщение об ошибке пользователю Обратите внимание, что при создании составного индекса важен порядок столбцов.
Если вы поместите менее селективные столбцы в качестве ведущих столбцов в индексе и поместите наиболее селективные столбцы в конце, другие запросы, которые имеют условие для не ведущих столбцов индекса, также могут воспользоваться преимуществом INDEX SKIP SCAN. Вам может понадобиться добавить еще один индекс, чтобы воспользоваться ими, но это сильно зависит от базы данных.
3) Сочетание обоих
Можно прочитать о комбинации обоих, но мне нравится только номер один.