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つの異なるモデル( uservisitorおよびcustomer )があり、それぞれが共通の検証を使用する必要がある場合はどうでしょう。 この場合、 validatesvalidates_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 
これは、おそらく、新しいレベルの柔軟性の第一印象を作るのに十分でしょう。

Source: https://habr.com/ru/post/J82841/


All Articles