开发者

Ruby on Rails ActiveRecord "has_many :through" uniqueness validation

Currently I insert a new relationship by everytime ch开发者_如何转开发ecking, if it doesn't exist:

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

How could I implement such validation inside the Relationship model, so that it wouldn't allow to have more than one relationship between the same entry and tag?


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


Assuming your models look something like this:

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

You could add a unique validation to your Relationship join model:

validates_uniqueness_of :tag_id, :scope => :entry_id

The validates_uniqueness_of method will ensure that the Relationship doesn't already exist, and the :scope option will scope the match to the given column. The SQL generated by rails via this validation will look like:

SELECT `relationships`.id
FROM `relationships`
WHERE (`relationships`.`tag_id` = <tag id> AND `relationships`.`entry_id` = <entry id>)
LIMIT 1

(which you'll notice is essentially the same SQL generated by your explicit use of Relationship.exists?(:entry_id => entry.id, :tag_id => tag.id)), and if a record is found, validation will fail.

As well, as with any case where you want to validate uniqueness, ensure that you have a unique key on tag_id, entry_id in your relationships table. See this article and the "Concurrency and integrity" of the API page I linked above for more info.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜