2011-07-06 6 views
0

私はテーブルの中でカラムの組み合わせが一意であるかどうかを検証するカスタムバリデータをRails 3.0で作成しました。検証の全体のコードは次のとおりです。文がしなければ、私はdef attribute_and_project_exist?方法と第二if文でunless条件を置き換えることができるように期待していたものを認識することは容易ではないカスタム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 

に留意されたいです。方法はdef attribute_or_project_changed?である。しかし、これらのメソッドを作成するときは、カプセル化のためにvalidates_eachの引数は渡されません。

質問:モデルで列名を使用できるように、2つの新しく作成されたメソッドでこれらの変数に何らかの方法でアクセスできるようにする方法がありますか、各引数を渡すか条件文を読みにくくするか、もう一度読みますか?

ありがとうございます!

答えて

1

私はあなたが一つの変数、1つのラムダ、および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

面白いやり方はコードを変更することです。このように処理時間が失われていないように見えるので、分かりやすくするために私が好きな命名規則を使うようになるでしょう。私の唯一の予約は非常にレール感を感じないということです。つまり、私はまだ私がこのバージョンを私の上に採用するだろうと思っています。ありがとうムー! –

+0

@Manocho:私は非常に幅広く多様な言語/環境/背景を持っています。だから私のものは、食べる人とは違うかもしれません。たとえば、私はlambdaがRailsコードでそれほど使われていないと見ていますが、それは私が見ているコードに過ぎません。まず、明確にするために最適化してください。(a)パフォーマンスの問題があり、(b)それがどこにあるか(プロファイリング経由で)知るまで、どれくらい速くなるか心配しないでください。 –

+0

私には良いアドバイスのような音:) –

関連する問題