2011-08-15 59 views
3

我有一個模型需要不同的驗證器,具體取決於它的當前狀態。我應該如何去調用每個實例的ActiveRecord驗證器?我想重複儘可能多的管道,但我不知道如何繼續。如何調用ActiveRecord驗證器作爲實例方法(ala Sequel)?

class Order < ActiveRecord::Base 
    attr_accessible :state 

    validate :state_specific_validations 

    def state_specific_validations 
    if :paid == self.state 
     # Warning: here be Unicorns... 

     # Wishful thinking... 
     validate_presence_of :paid_at 
     validate_associated :purchaser 

     # Hopeful. What are the validators called internally in Rails? 
     errors << PresenceValidator.new(self, :paid_at).valid? 
     errors << AssociationValidator.new(self, :paid_at).valid? 

     # Plan B 
     # ... Hoping for help from the audience ... 

    else 
     # Even more complicated validator logic, hoping for some DRY validators 
    end 
    end 
end 

我可以使用自定義的驗證,但爲什麼我需要複製所有內置的驗證邏輯(i18n的錯誤信息等)?

是否有一種調用Rails驗證器作爲實例方法的簡潔方法? 我認爲Sequel基於實例的驗證器的方法比ActiveRecord的基於類的驗證器更合理,但我不是在這裏進行判斷。我只想回到解決更有趣的問題。我只是希望別人能夠遇到這個問題,並且可以指點我一些有趣的要點或寶石。

回答

4

我敢肯定所有的validate_*方法可以採取:if選項 - 它可以指向另一個方法(可能接受一個Proc也一樣),所以你可以打破你的驗證更是這樣的:

validates_presence_of :paid_at, :if => :paid? 
validates_association :purchaser, :if => :paid? 

爲了進一步清理東西,還有的with_options幫手:

如果
with_options :if => :paid? do |v| 
    v.validates_presence_of :paid_at 
    v.validates_association :purchaser 
end 

也不清楚可以與標準validate :custom_validate_method雖然可以使用 - 但它不會讓我感到吃驚。

+0

帕特,感謝您的輸入。 'with_options'是我將來肯定會使用更多的東西。看起來我可能正在使用您的解決方案,但您是否可以先看看我發佈的答案?我不確定紅寶石單體是否會扭曲我的大腦。 :) – pithyless

0

這有什麼不合適的理由嗎?好像它可能工作,但也許元編程扭曲我的大腦......

class Order < ActiveRecord::Base 
    attr_accessible :state 

    validate :state_specific_validations 

    def state_specific_validations 
    if :paid == self.state 
     class << self 
     validate_presence_of :paid_at 
     validate_associated :purchaser 
     end 
    end 
    end 
end 

糟糕的是,測試都通過,所以我不知道,如果我解決它還是我需要更好的測試。例如,我不是100%肯定這個單身修改不會影響其他訂單。

嘆息需要一些睡眠。

+0

這裏的問題是您在驗證過程中在類級別(授予,而不是Order,僅僅是特徵類)添加事物。也許它有效,但感覺非常脆弱。我根本不會推薦這種方法。 – pat

相關問題