2011-07-06 54 views
0

我在Rails 3.0中創建了一個自定義驗證器,驗證列的組合是否在表中唯一。驗證的完整代碼是:使用方法澄清自定義Rails 3.0驗證

class UniqueInProjectValidator < ActiveModel::EachValidator 

    def validate_each(object, attribute, value) 
    unless object.class.where("project_id = ? AND #{attribute} = ?", object.project_id, value).empty? 
     if object.new_record? 
     object.errors[attribute] << (options[:message] || "must be unique in each project") 
     else 
     orig_rec = object.class.find(object.id) 
     if value != orig_rec.method(attribute).call || object.project_id != orig_rec.project_id 
      object.errors[attribute] << (options[:message] || "must be unique in each project") 
     end 
     end 
    end 

end 

請注意,這是不容易認識到什麼的if語句做的,所以我希望能夠與def attribute_and_project_exist?方法,第二if語句來代替unless條件採用def attribute_or_project_changed?方法。但是,在創建這些方法時,來自validates_each的參數因封裝而不通過。

現在的問題:是否有辦法以某種方式乾淨地允許我的兩個新創建的方法訪問這些變量,就像我們可以對模型中的列名所做的那樣,或者我堅持使用傳遞每個參數或者讓讀者難以閱讀條件陳述?

在此先感謝!

回答

1

我想你可以清理有點用一個變量,一個拉姆達,和一個「儘快恢復」:

def validate_each(object, attribute, value) 
    # If there is no duplication then bail out right away as 
    # there is nothing to check. This reduces your nesting by 
    # one level. Using a variable here helps to make your 
    # intention clear. 
    attribute_and_project_exists = object.class.where("project_id = ? AND #{attribute} = ?", object.project_id, value).empty? 
    return unless attribute_and_project_exists 

    # This lambda wraps up your second chunk of ugly if-ness and saves 
    # you from computing the result unless you have to. 
    attribute_or_project_changed = lambda do 
    orig_rec = object.class.find(object.id) 
    value != orig_rec.method(attribute).call || object.project_id != orig_rec.project_id 
    end 

    # Note that || short-circuits so the lambda will only be 
    # called if you have an existing record. 
    if object.new_record? || attribute_or_project_changed.call 
    object.errors[attribute] << (options[:message] || "must be unique in each project") 
    end 
end 

我不知道要好上多少比你的原創,但邏輯和控制流程更清晰,由於更好的塊。

+0

有趣的方式來改變代碼。似乎沒有處理時間以這種方式丟失,我會使用我喜歡的命名約定來清晰。我唯一的保留是它不覺得非常rails-y。也就是說,我仍然認爲我會採用這個版本,除非有什麼更快的事情發生。謝謝畝! –

+0

@Manocho:我擁有相當廣泛和多樣的語言/環境/背景,所以我的接觸可能會不同於吃Rails和呼吸的人;例如,我沒有看到lambdas在Rails代碼中使用過那麼多,但這可能只是我所看到的代碼。首先優化清晰度,不要擔心它的速度有多快,直到(a)出現性能問題,並且(b)您知道(通過分析)它在哪裏。 –

+0

聽起來像對我好的建議:) –