Вы можете добавить уникальность в таблицу соединений
add_index :users_roles, [ :user_id, :role_id ], :unique => true, :name => 'by_user_and_role'
см. Какой наилучший способ для обхода отсутствия в Rails составного ключа в таблице соединений?
Тогда ваша база данных вызовет исключение, которое вы должны обработать.
Я не знаю какой-либо готовой проверки рельсов для этого случая, но вы можете добавить свою собственную проверку следующим образом:
class User < ActiveRecord::Base
has_and_belongs_to_many :roles, :before_add => :validates_role
Я бы просто молча отбросил вызов базы данных и сообщил об успехе.
def validates_role(role)
raise ActiveRecord::Rollback if self.roles.include? role
end
ActiveRecord :: Откат захвачен изнутри, но не восстановлен.
Редактировать
Не используйте ту часть, где я добавляю пользовательскую проверку . Это вроде работает, но есть лучшие альтернативы.
Используйте параметр :uniq
для ассоциации, как @Spyros предложил в другом ответе:
class Parts < ActiveRecord::Base
has_and_belongs_to_many :assemblies, :uniq => true, :read_only => true
end
(этот фрагмент кода взят из Rails Guides v.3). Читайте о Rails Guides v 3.2.13 ищите 4.4.2.19: uniq
Rails Guide v.4 специально предупреждает против использования include?
для проверки уникальности из-за возможных условий гонки.
Остается часть о добавлении индекса в таблицу соединений.