Ruby on Rails ActiveRecord“has_many:through”唯一性validation

目前我每次检查都会插入一个新的关系,如果它不存在:

unless Relationship.exists?(:entry_id => entry.id, :tag_id => tag.id) 

我如何在关系模型中实现这样的validation,以便它不允许在同一条目和标记之间有多个关系?

 class Relationship < ActiveRecord::Base belongs_to :entry belongs_to :tag validates :tag_id, :uniqueness => { :scope => :entry_id } end 

假设您的模型看起来像这样:

 class Entry < ActiveRecord::Base has_many :relationships has_many :tags, :through => :relationships end class Tag < ActiveRecord::Base has_many :relationships has_many :entries, :through => :relationships end class Relationship < ActiveRecord::Base belongs_to :entry belongs_to :tag end 

您可以为Relationship join模型添加唯一的validation:

 validates_uniqueness_of :tag_id, :scope => :entry_id 

validates_uniqueness_of方法将确保关系不存在,并且:scope选项将匹配范围限定为给定列。 rails通过此validation生成的SQL将如下所示:

 SELECT `relationships`.id FROM `relationships` WHERE (`relationships`.`tag_id` =  AND `relationships`.`entry_id` = ) LIMIT 1 

(您会注意到与您显式使用Relationship.exists?(:entry_id => entry.id, :tag_id => tag.id)生成的SQL基本相同Relationship.exists?(:entry_id => entry.id, :tag_id => tag.id) ),如果找到记录,validation将失败。

同样,对于要validation唯一性的任何情况,请确保在relationships表中的tag_id, entry_id上有唯一键。 有关详细信息,请参阅此文章以及我上面链接的API页面的“并发性和完整性”。