まったり Rails (その6)
さて、scaffoldも動いたので次はバリデーション。ここはさらっと流そう。
RailsのバリデーションはActiveRecordのモデルクラスに書く。
バリデーションのためのメソッドはその用途により"validates_〜"というプレフィクスが付いたものを使用する。
ActiveRecord::Validations::ClassMethods
例えば代表的なバリデーションである「なにかが入力されているか」、つまりはフィールドが空かどうかを検査するためのメソッドは以下のように記述する
- products.rb
class Product < ActiveRecord::Base validates_presence_of :title, :description, :image_url end
パラメタには対象のフィールド(のシンボル)を一つ以上、幾つでもセット出来る。このケースではモデルで定義した'tile'、'description'、'image_url'に対応する入力値に対してバリデーションが実施される訳だ。
実際のバリデーションの結果、エラーと判定された場合は前エントリのようにフィールドのボーダーが赤く縁取りされ、上部にエラーが発生している事を通知するエリアが表示される
スクリーンショットはIE7で表示した結果だが、エラーを示す縁取りがはみ出てしまっており、酷い見栄えだ。スタイルシートの互換性の問題だろうか。
これでバリデーションはできるようになったがエラーの通知表示が英語なのが気に入らない。やはり自国語にしたい所だ。ビューは現在scaffoldingで動的に生成しているため手を出せないが(scaffoldを使用せずに自らビューをカスタマイズしていくことも、当然できるのだが、それはこの後のお楽しみ)、取りあえずエラーメッセージだけでも日本語にしておきたい。しかし、これは本当に簡単だ。
- products.rb
class Product < ActiveRecord::Base validates_presence_of :title, :description, :image_url, :message => 'は必ず入力してください' end
このように:messageシンボルをキーに持つハッシュをパラメタに指定してやるだけだ。
しかし、この部分は一体どのようにして実装されているのだろう。例えばパラメタは配列を用いた可変引数だが、最後のパラメタだけはハッシュであり用途が全然違う(デフォルトの動作を変更するオプションパラメタのようだ)
非常に興味深かったためactive_recoed/validation.rb内の同メソッドのソースコードを読んでみることにした。
- validates_presence_ofメソッドより抜粋
def validates_presence_of(*attr_names) configuration = { :message => ActiveRecord::Errors.default_error_messages[:blank], :on => :save } configuration.update(attr_names.extract_options!) send(validation_method(configuration[:on])) do |record| unless (configuration[:if] && !evaluate_condition(configuration[:if], record)) || (configuration[:unless] && evaluate_condition(configuration[:unless], record)) record.errors.add_on_blank(attr_names, configuration[:message]) end end end
このメソッドでもデフォルトのエラーメッセージはErrorクラスのアクセサであるActiveRecord::Errors.default_error_messages[:blank]に対応する値、つまり"can't be blank"が使われるのだが、メソッドパラメタの末尾に':message'で指定されたハッシュを見つけるとその値で置き換えているわけだ。
ちなみに、configuration.update(attr_names.extract_options!)は、指定されたパラメタ中からハッシュだけを抽出して(配列部分は使わない)、ローカルで用意したハッシュとマージしており、指定されたオプションだけがデフォルトに換わって使われる。(この部分、恥ずかしながら最初の10分は何をしているのかさっぱり解らなかった。特に凄いのがextract_options!メソッドだが、この部分はキーワード引数(のようなもの?)をハッシュで実装しているから必要なコードであり、今後のRubyのバージョンでは書き換わる可能性もあるんだろうか。)
validates_presence_ofメソッドはソースを読めば解るが、他にもオプションがあり、動作をカスタマイズできる。
Railsのような抽象度の高い本格的なフレームワークはソースコードが読めると理解度が全く違うし、そもそも学習のために非常に参考になるソースコードが多い。(慣れない内はちんぷんかんぷんなものも多いが)
あ、結局「さらっ」と流すことなんて出来なかったな。