【发布时间】:2011-02-26 20:57:59
【问题描述】:
目前我通过每次检查插入一个新关系,如果它不存在:
unless Relationship.exists?(:entry_id => entry.id, :tag_id => tag.id)
我怎样才能在关系模型中实现这样的验证,这样它就不允许在同一个条目和标签之间有多个关系?
【问题讨论】:
标签: ruby-on-rails activerecord
目前我通过每次检查插入一个新关系,如果它不存在:
unless Relationship.exists?(:entry_id => entry.id, :tag_id => tag.id)
我怎样才能在关系模型中实现这样的验证,这样它就不允许在同一个条目和标签之间有多个关系?
【问题讨论】:
标签: ruby-on-rails activerecord
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 加入模型添加唯一验证:
validates_uniqueness_of :tag_id, :scope => :entry_id
validates_uniqueness_of 方法将确保关系不存在,:scope 选项将匹配范围限定为给定列。 rails 通过此验证生成的 SQL 如下所示:
SELECT `relationships`.id
FROM `relationships`
WHERE (`relationships`.`tag_id` = <tag id> AND `relationships`.`entry_id` = <entry id>)
LIMIT 1
(您会注意到这与您显式使用 Relationship.exists?(:entry_id => entry.id, :tag_id => tag.id) 生成的 SQL 基本相同),如果找到记录,验证将失败。
此外,与任何要验证唯一性的情况一样,请确保在 relationships 表中的 tag_id, entry_id 上具有唯一键。有关详细信息,请参阅this article 和我上面链接的 API 页面的“并发性和完整性”。
【讨论】:
add_index :relationships, [:tag_id, :entry_id], :unique => true。然后,做你的 DBMS,只有当两列的值都与现有行匹配时,新行才会发生冲突。