所以我有这两个模型:
class Tag < ActiveRecord::Base
has_many :event_tags
attr_accessible :tag_id, :tag_type, :value
end
class EventTag < ActiveRecord::Base
belongs_to :tag
attr_accessible :tag_id, :event_id, :region
end
和这个标签表:
**tag_id** **tag_type** **value**
1 "funLevel" "Boring..."
2 "funLevel" "A Little"
3 "funLevel" "Hellz ya"
4 "generic" "Needs less clowns"
5 "generic" "Lazer Tag"
...
我想做的是编写一个自定义验证,它会检查:
例如:
t1 = EventTag.new(:tag_id => 1, :event_id =>777, :region => 'US')
t1.save # success
t2 = EventTag.new(:tag_id => 2, :event_id =>777, :region => 'US')
t2.save # failure
# because (event_id: 777) already has a tag_type of
# "funLevel" associated with it
t3 = EventTag.new(:tag_id => 4, :event_id =>777, :region => 'US')
t3.save # success, because as (tag_id:4) is not "funLevel" type
我想出了一个丑陋的解决方案:
def cannot_have_multiple_funLevel_tag
list_of_tag_ids = EventTag.where("event_id = ?", event_id).pluck(:tag_id)
if(Tag.where("tag_id in ?", list_of_tag_ids).pluck(:tag_type).include? "funLevel")
errors.add(:tag_id, "Already has a Fun Level Tag!")
end
刚开始使用rails,是否有更好/更优雅/更便宜的方式?
答案 0 :(得分:0)
您的数据结构化方式意味着内置的Rails验证可能不会成为您的一大堆帮助。 如果 funLevel
类可以直接访问EventTag
属性,您可以使用以下内容:
# event_tag.rb
validate :tag_type, uniqueness: { scope: :event_id },
if: Proc.new { |tag| tag.tag_type == "funLevel" }
(不幸的是,从快速测试中,您似乎无法验证虚拟属性的唯一性。)
如果没有这个,你可能会使用自定义验证。您自定义验证的明显改进(假设您希望在EventTag
上进行验证)将不会运行验证,除非EventTag
是funLevel
标记:
def cannot_have_multiple_funLevel_tag
return unless self.tag.tag_type == "funLevel"
...
end