Rails 3の検証に対する新しいアプローチ

はじめに



あなたはすでに同志のポストから知っているように Rails 3.0のActiveModel抽象化に関するYehuda Katzには、ActiveRecordに検証モジュールなどのActiveModelのいくつかの側面が含まれるようになりました。



そして、始める前に、すでに持っている検証方法を思い出しましょう。 それらのすべてはまだ動作中ですが、Rails 3はいくつかの新しい素晴らしい代替手段を提供します。



新しいvalidate



方法



validate



メソッドは、検証オプション付きの属性とハッシュを受け入れます。 これは、通常の検証を次のように記述できることを意味します。

 class Person < ActiveRecord::Base validates :email, :presence => true end
      
      





転送できるオプションは次のとおりです。 これにより、特定の属性に対して非常にシンプルで簡潔なオプションの広範な領域が提供され、必要なすべての検証を1か所に書き込むことができます。



たとえば、名前とメールを確認する必要がある場合は、次の操作を実行できます。

 class User < ActiveRecord::Base validates :name, :presence => true, :length => {:minimum => 1, :maximum => 254} validates :email, :presence => true, :length => {:minimum => 3, :maximum => 254}, :uniqueness => true, :format => {:with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[az]{2,})$/i} end
      
      



したがって、モデルをすぐに見て、各属性にどの検証がハングしているのかを確認できます-コードと可読性にわずかな勝利があります:)



使い慣れたユースケースの取得



ただし、 :format => {:with => EmailRegexp}



を書くことは、いくつかの場所で書くのが少し重いです。これは、他のモデルに適用できる再利用可能な検証を作成するアイデアを示唆しています。



先に進みましょう-そして、Googleがどれだけかっこいいかを示すために、数文字以上の表現力豊かな正規表現を使用する必要がある場合はどうでしょうか。 :)



まあ、検証も手書きで書くことができます。 まず、アプリケーションの腸内のlib



ディレクトリにemail_validator.rb



ファイルを作成します。

 # lib/email_validator.rb class EmailValidator < ActiveModel::EachValidator EmailAddress = begin qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]' dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]' atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-' + '\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+' quoted_pair = '\\x5c[\\x00-\\x7f]' domain_literal = "\\x5b(?:#{dtext}|#{quoted_pair})*\\x5d" quoted_string = "\\x22(?:#{qtext}|#{quoted_pair})*\\x22" domain_ref = atom sub_domain = "(?:#{domain_ref}|#{domain_literal})" word = "(?:#{atom}|#{quoted_string})" domain = "#{sub_domain}(?:\\x2e#{sub_domain})*" local_part = "#{word}(?:\\x2e#{word})*" addr_spec = "#{local_part}\\x40#{domain}" pattern = /\A#{addr_spec}\z/ end def validate_each(record, attribute, value) unless value =~ EmailAddress record.errors[attribute] << (options[:message] || " ") end end end
      
      





lib



ディレクトリからの各ファイルは自動的にロードされ、バリデーターはActiveModel::EachValidator



から継承されるため、 ActiveModel::EachValidator



の名前はActiveModel::Validations



アクセスできるオブジェクトで使用できる動的バリデーターとして使用されます。 つまり、たとえば、これらはすべてActiveRecordオブジェクトです。



動的バリデーターの名前は、「Validator」という単語の左側にあるすべてのもので、小文字に変換されます。



したがって、 User



クラスは次のようになります。

 # app/models/person.rb class User < ActiveRecord::Base validates :name, :presence => true, :length => {:minimum => 1, :maximum => 254} validates :email, :presence => true, :length => {:minimum => 3, :maximum => 254}, :uniqueness => true, :email => true end
      
      





注意してください:email => true



? 非常に簡単ですが、最も重要なのは、どこでも使用できることです!



コンソールには、次のようなものが表示されます(独自のメッセージ「正しくない」):

 $ ./script/console Loading development environment (Rails 3.0.pre) ?> u = User.new(:name => 'Mikel', :email => 'bob') => #<User id: nil, name: "Mikel", email: "bob", created_at: nil, updated_at: nil> >> u.valid? => false >> u.errors => #<OrderedHash {:email=>[" "]}>
      
      





クラスの検証



しかし、たとえば、3つの異なるモデル( user



visitor



およびcustomer



)があり、それぞれが共通の検証を使用する必要がある場合はどうでしょう。 この場合、 validates



validates_with



に置き換え、これを行うだけです:

 # app/models/person.rb class User < ActiveRecord::Base validates_with HumanValidator end # app/models/person.rb class Visitor < ActiveRecord::Base validates_with HumanValidator end # app/models/person.rb class Customer < ActiveRecord::Base validates_with HumanValidator end
      
      





そして、 lib



ディレクトリにファイルを置きます:

 class HumanValidator < ActiveModel::Validator def validate(record) record.errors[:base] << "This person is dead" unless check(human) end private def check(record) (record.age < 200) && (record.age > 0) end end
      
      





そして、明らかにはるかにフェッチされた例をチェックしてください:

 $ ./script/console Loading development environment (Rails 3.0.pre) >> u = User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil> >> u.valid? => false >> u.errors => #<OrderedHash {:base=>["This person is dead"]}>
      
      





トリガー時間



予想どおり、各検証では次のサブオプションを使用できます。

それぞれが任意のメソッドの呼び出しを取得できます。 このように:

 class Person < ActiveRecord::Base validates :post_code, :presence => true, :unless => :no_postcodes? def no_postcodes? true if ['TW'].include?(country_iso) end end
      
      



これは、おそらく、新しいレベルの柔軟性の第一印象を作るのに十分でしょう。



All Articles