0

所以我有这两个模型:

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"
    ...

我想做的是编写一个自定义验证,它会检查以查看:

  • 每个 event_id附加一个 tag_type 的“funLevel”,但可以有多个“通用”标签

例如:

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 新手,有没有更好/更优雅/更便宜的方法?

4

1 回答 1

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
于 2013-03-20T23:53:41.417 回答