アインシュタインの電話番号
2011.04.18
SinatraからActiveRecord 3を使う(3) バリデーション

前回のCRUD操作に引き続き、今回はSinatraからActiveRecord 3を使った際の入力した値のバリデーション(検証)について調べたのでメモ。

バリデーション

バリデーションを行うには、モデルクラスにその行いたいバリデーション用のメソッドと対象のカラムをシンボル名で記述する。バリデーションは最初からいくつかのパターンが組み込まれていて、その記述は基本的に以下のような書式になる。

validates_バリデーションする方法名_of バリデーション対象のカラムのシンボル名

たとえば、ユーザー名がかぶらない(ユニーク)な状態にしたいのであれば、

validates_uniqueness_of :user

のような感じになる。組み込みで用意されているバリデーションの一覧については、こちらの記事が詳しい。実際に、前回までに作ったカウントするだけのSinatraアプリをベースにして、例えば以下のような感じでバリデーションを記述してみる。

class Count < ActiveRecord::Base
  validates_presence_of :user  # ユーザー名の値が存在すること(空じゃないこと)
  validates_uniqueness_of :user  # ユーザー名の値がユニークであること(重複してないこと)
  validates_length_of :user, :maximum => 7, :minimum => 3  # ユーザー名の長さが3文字以上7文字以下であること
end

バリデーションが実行されるメソッド

上記のバリデーションをモデルクラスに設定した場合、実際にそのバリデーションが実行されるタイミング(メソッド)は、save(save!)メソッドとvalid?メソッドがメインになる気がする。savevalid?以外にもバリデーションを呼び出すメソッドは存在するけど今回は割愛。

saveメソッド

saveメソッドを実行したときに、バリデーションに失敗すれば、DBへの書き込みは行われず、saveメソッドからはfalseの戻り値が返る。

get '/validate1' do
  c = Count.new
  c.user = 'hogehoge'  # バリデーションで7文字以内なのに、8文字の文字列を挿入している
  c.save  #=> バリデーションで失敗するので、DBには保存されず、戻り値はfalse
end

よって、上記のコードはDB側から見た場合は何も起きなかったことと等しい。

save!メソッド

バリデーションに失敗しているときに、例外を発生させたいときは、save!メソッドを使う。save!メソッドを使うと、バリデーションに失敗したときにActiveRecord::RecordInvalidの例外が発生する。

get '/validate1' do
  c = Count.new
  c.user = 'hogehoge'  # バリデーションで7文字以内なのに、8文字の文字列を挿入している
  c.save!  #=> バリデーションに失敗し、DBには保存されず、ActiveRecord::RecordInvalidの例外が発生
end
ActiveRecord::RecordInvalid at /validate2
Validation failed: User is too long (maximum is 7 characters)

例外のメッセージは上記のような感じ。

valid?メソッド

純粋にバリデーションだけを実行したい場合は、valid?メソッドがある。これは保存等のDB操作はせず、バリデーションに成功するかどうかだけを実行し結果をBooleanで返す。

get '/validate3' do
  c = Count.new
  c.user = 'hogehoge'  # 正しくない
  c.valid?  #=> false
  c.user = 'hoge'  # 正しい
  c.valid?  #=> true
end

1つでも失敗すると、何も保存されない

バリデーションに1つでも失敗すると、そのオブジェクトに対して行われたすべての変更が保存されない。

get '/validate4' do
  c = Count.new
  c.count = 5  # 正しい
  c.user = 'hogehoge'  # 正しくない
  c.save  #=> 何も保存されない
  c.save!  #=> 何も保存されない&例外発生
end

上記の場合、c.userのバリデーションに失敗しているので、c.countは正しくても、c.save後には何も保存されない。最初はうまくいった部分のc.countだけ保存されるかなと思ったけど、やってみたらそうではなかった。

エラー情報

バリデーションに失敗した情報は、errorsオブジェクトに格納されている。バリデーションが一度も実行されていない場合はerrorsオブジェクトは空っぽ。バリデーションが実行され、失敗した場合のみ情報が格納される。

get '/validate5' do
  c = Count.new
  c.user = 'hogehoge'  # 正しくない
  c.errors  #=> バリデーションが実行されていないので空っぽ
  c.valid?  # バリデーション実行
  c.errors  #=> [:user, "is too long (maximum is 7 characters)"]
end

バリデーションを実行したくない場合

バリデーションを実行したくない場合は、saveメソッドの引数で:validate => falseを渡すと、その時はバリデーションを実行せずに保存することが可能になる。

get '/validate6' do
  c = Count.new
  c.user = 'hogehoge'  # 正しくない
  c.save(:validate => false)  #=> 正しくないけど保存される
end

これでバリデーションについての基本的な使い方は、ひと通り抑えることができたと思う。さらに詳しくは、今回参考にさせてもらったRails 3のガイドを和訳してくれているページが、自分の知っている範囲では今のところActiveRecord 3のバリデーションについての情報が多かった。
次回は、ActiveRecord 3用機能拡張gemのMetaWhereを解説する予定。


ruby/rails/RailsGuidesをゆっくり和訳してみたよ/Active Record Validations and Callbacks - 株式会社ウサギィwiki ActiveRecordが提供するModel機能を理解しよう - @IT