こんにちは。まっつんです。今回は 第 2 回 で実装しなかったバリデーションを実装します。
Ruby on Rails (以下、Rails) ではモデルにバリデーションを実装します。簡単なバリデーションであれば、定義済みのバリデーションヘルパーを使って容易に実装することができます。
容易に実装できるにも関わらず、第 2 回 では実装を見送りました。これには 2 つの理由があります。
最初の理由はバリデーションを実行するタイミングにあります。デフォルトではモデルがデータベースに保存される時にバリデーションが実行されます。よって、ポテトバーガー注文アプリケーションのメインメニューが選択された時、そしてサイドメニューが選択された時にそれぞれバリデーションを実行するには独自の実装が必要となります。
次により重要な理由として、普段から特に意識することなく行っているバリデーションという処理を考えるということがあります。
そこで、まずバリデーションを実装し、そのあとでバリデーションについて考えてみたいと思います。
バリデーションの実装
バリデーションの実装は以下のようになります。バリデーションに関するメソッドはすべてモデルに実装し、コントローラから呼び出すようにします。
- プロパティごとのバリデータメソッドを用意する
- コントローラから呼び出すことができるバリデーションメソッドをモデルに用意する
- 実行のタイミングに関わらず、プロパティ毎のバリデータメソッドを呼び出す
app/models/order.rb
class Order < ActiveRecord::Base
belongs_to :customer
validate :validator_of_main, :validator_of_side
def invalid_for_main_menu?
errors.clear
validator_of_main
return errors.count > 0
end
def invalid_for_side_menu?
errors.clear
validator_of_side
return errors.count > 0
end
def validator_of_main
errors.add(:main, '正しい注文内容を選択してください') if
main.blank? or ![1, 2, 3].include?(main)
end
def validator_of_side
errors.add(:side, '正しいサイドメニューを選択してください') if
side.blank? or ![1, 2, 3].include?(side)
end
end
Rails のドキュメント「Active Record Validations and Callbacks」の「6 Creating Custom Validation Methods」を参考に、メインメニュー (main フィールド), サイドメニュー (side フィールド) のバリデータメソッドとしてそれぞれ validator_of_main, validator_of_side を実装しています。また、これらのメソッドが validate メソッドの引数になっていることに注意してください。これによってデフォルトのバリデーションの際にも validator_of_main, validator_of_side が呼び出されるようになります。
invalid_for_main_menu?, invalid_for_side_menu? はコントローラから呼び出されるメソッドです。エラーをクリアして、バリデータメソッドを呼び出し、結果を返しています。
バリデーションの実行
続いて、実装したバリデーションをコントローラから呼び出すようにします。
app/controllers/orders_controller.rb
class OrdersController < ApplicationController
...
def side_menu
@order = Order.new
@order.main = params[:main]
render :action => 'main_menu', :status => 400 and return if @order.invalid_for_main_menu?
end
def confirmation
@order = Order.new
@order.main = params[:main]
@order.side = params[:side]
render :action => 'main_menu', :status => 400 and return if @order.invalid_for_main_menu?
render :action => 'side_menu', :status => 400 and return if @order.invalid_for_side_menu?
main_index = @order.main - 1
side_index = @order.side - 1
@main = ['ジャーマンポテトバーガー', 'ポテトコロッケバーガー', '肉じゃがバーガー'][main_index]
@side = ['フライドポテト', 'ポテトサラダ', 'スイートポテト'][side_index]
@price = [650, 600, 700][main_index]
end
def create
@order = Order.new(params[:order])
if @order.save
render :action => 'finish'
else
render :action => 'main_menu', :status => 400
end
end
...
end
side_menu メソッドではメインメニューのバリデーション、confirmation メソッドではメインメニューとサイドメニューのバリデーションを行っています。バリデーションに失敗した場合は HTTP ステータスコード 400 (Bad Request) を返し、該当するメニューのページを表示します。
また、データベースへの保存に失敗した場合は、バリデーションに失敗したものと見なし、HTTP ステータスコード 400 (Bad Request) を返し、メインメニューを表示します。
エラーの表示
メインメニューとサイドメニューの選択ページで発生したエラーが表示されるようにビューを変更します。
app/views/orders/main_menu.html.erb
<h3>ご注文は何になさいますか?</h3> <%= error_messages_for :order %> <ul> ...
app/views/orders/side_menu.html.erb
<h3>サイドメニューは何になさいますか?</h3> <%= error_messages_for :order %> <ul> ...
エラーの表示に関する詳細については、Rails のドキュメント「Active Record Validations and Callbacks」の「8 Displaying Validation Errors in the View」をご覧ください。
それではアプリケーションを実行してみましょう。URI のリクエストパラメータを変更することでエラーの動作確認を行うことができます。
おわりに
今回はバリデーションの実装を中心に解説しました。
今回のアプリケーションは当初データベースへ保存する部分以外はセッションを使って実装を行いました。しかし、RESTful なアプリケーションを作成するという観点から実装を見直し、現在の形になりました。その甲斐あって、全体的にシンプルでわかりやすい実装になったのではないかと思います。
このチャレンジは今回で終了する予定だったのですが、予定を変更してもう 1 回書くことにしました。次回はポテトバーガー注文アプリケーションをそのまま利用して、JavaScript によるクライアントを実装します。
使用したソフトウェアのバージョン
| Ruby on Rails | 2.3.2 |
|---|
参考文献
トラックバック(0)
- このブログ記事のトラックバックURL:
