2013-03-20 35 views
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" 
    ... 

我希望做的是寫一個自定義驗證,它檢查看:

  • 每個事項標識有「funLevel」 ATT的只有一個 TAG_TYPE真想給它,但可以有一個以上的「通用」標籤

例如:

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 

作爲新軌道,有沒有更好/更優雅/更便宜的方法?

回答

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 
+0

呀,由於沒有完全控制數據庫,即時通訊工具被迫與我有什麼關係。我喜歡你的自定義驗證器的替代品,不認爲我可以使用標籤模型作爲屬性。 – mypark 2013-03-21 03:08:18

+0

是的,關聯添加了一堆方法,使相關模型的訪問和交互變得非常簡單。如果你在閱讀心情,請查看[Association Basics](http://guides.rubyonrails.org/association_basics.html)Rails指南,特別是[詳細的關聯參考](http:// guides。 rubyonrails.org/association_basics.html#detailed-association-reference)。 – 2013-03-21 04:46:44