はじめに
あなたはすでに同志のポストから知っているように Rails 3.0のActiveModel抽象化に関するYehuda Katzには、ActiveRecordに検証モジュールなどのActiveModelのいくつかの側面が含まれるようになりました。
そして、始める前に、すでに持っている検証方法を思い出しましょう。
-  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 -  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 -  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 -  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 -  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 -  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 -  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 -  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 -  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 -  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 -  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 -  
validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
 
 新しいvalidate
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    方法 
      validate
      
      メソッドは、検証オプション付きの属性とハッシュを受け入れます。 これは、通常の検証を次のように記述できることを意味します。
 class Person < ActiveRecord::Base validates :email, :presence => true end
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      転送できるオプションは次のとおりです。
-  
:acceptance => Boolean :confirmation => Boolean :exclusion => { :in => Ennumerable } :inclusion => { :in => Ennumerable } :format => { :with => Regexp } :length => { :minimum => Fixnum, maximum => Fixnum, } :numericality => Boolean :presence => Boolean :uniqueness => Boolean
 -  
:acceptance => Boolean :confirmation => Boolean :exclusion => { :in => Ennumerable } :inclusion => { :in => Ennumerable } :format => { :with => Regexp } :length => { :minimum => Fixnum, maximum => Fixnum, } :numericality => Boolean :presence => Boolean :uniqueness => Boolean
 -  
:acceptance => Boolean :confirmation => Boolean :exclusion => { :in => Ennumerable } :inclusion => { :in => Ennumerable } :format => { :with => Regexp } :length => { :minimum => Fixnum, maximum => Fixnum, } :numericality => Boolean :presence => Boolean :uniqueness => Boolean
 -  
:acceptance => Boolean :confirmation => Boolean :exclusion => { :in => Ennumerable } :inclusion => { :in => Ennumerable } :format => { :with => Regexp } :length => { :minimum => Fixnum, maximum => Fixnum, } :numericality => Boolean :presence => Boolean :uniqueness => Boolean
 -  
:acceptance => Boolean :confirmation => Boolean :exclusion => { :in => Ennumerable } :inclusion => { :in => Ennumerable } :format => { :with => Regexp } :length => { :minimum => Fixnum, maximum => Fixnum, } :numericality => Boolean :presence => Boolean :uniqueness => Boolean
 -  
:acceptance => Boolean :confirmation => Boolean :exclusion => { :in => Ennumerable } :inclusion => { :in => Ennumerable } :format => { :with => Regexp } :length => { :minimum => Fixnum, maximum => Fixnum, } :numericality => Boolean :presence => Boolean :uniqueness => Boolean
 -  
:acceptance => Boolean :confirmation => Boolean :exclusion => { :in => Ennumerable } :inclusion => { :in => Ennumerable } :format => { :with => Regexp } :length => { :minimum => Fixnum, maximum => Fixnum, } :numericality => Boolean :presence => Boolean :uniqueness => Boolean
 -  
:acceptance => Boolean :confirmation => Boolean :exclusion => { :in => Ennumerable } :inclusion => { :in => Ennumerable } :format => { :with => Regexp } :length => { :minimum => Fixnum, maximum => Fixnum, } :numericality => Boolean :presence => Boolean :uniqueness => Boolean
 -  
:acceptance => Boolean :confirmation => Boolean :exclusion => { :in => Ennumerable } :inclusion => { :in => Ennumerable } :format => { :with => Regexp } :length => { :minimum => Fixnum, maximum => Fixnum, } :numericality => Boolean :presence => Boolean :uniqueness => Boolean
 
たとえば、名前とメールを確認する必要がある場合は、次の操作を実行できます。
 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"]}>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      トリガー時間
予想どおり、各検証では次のサブオプションを使用できます。
-  
:on :if :unless :allow_blank :allow_nil
 -  
:on :if :unless :allow_blank :allow_nil
 -  
:on :if :unless :allow_blank :allow_nil
 -  
:on :if :unless :allow_blank :allow_nil
 -  
:on :if :unless :allow_blank :allow_nil
 
 class Person < ActiveRecord::Base validates :post_code, :presence => true, :unless => :no_postcodes? def no_postcodes? true if ['TW'].include?(country_iso) end end
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      これは、おそらく、新しいレベルの柔軟性の第一印象を作るのに十分でしょう。