【実践Rails学習ノート#4】例外処理500を実装する
前回に引き続き実践Ruby on Railsの学習ノートです。
今回は例外処理を行って例外ページに飛ばす、という機能を実装していきます。
以下のような流れで作っていきます。
- controllerでraiseして例外を発生させる
- 共通のcontrollerで例外処理を行う振る舞いとそのメソッドを定義
- さっき作ったメソッドでrenderされるviewを作成
関連記事
事前知識
例外とは
Railsプログラマが普段目にする例外は、Exceptionクラスそのもののインスタンスではなく、Exceptionクラスの子孫クラスのインスタンスです。
ということでRaisでは全ての例外はExceptionクラスを継承したなんらかのクラスのインスタンスということになるそうです。
というか正確には、Exception::StandardErrorを継承する感じになります。これはRailsというよりRubyのしきたりですねーー
http://qiita.com/kasei-san/items/75ad2bb384fdb7e05941
話を戻すと、
ActiveRecord::RecordNotFoundという例外の継承関係は、
ActiveRecord::ActiveRecordError <- StandardError <- Exception
といった形になっています。
pryとかでみてみたところ、ActiveRecordはモジュールとしてincludeされてるみたいですね。
例外の発生させ方
例外は以下のように、raiseメソッドを用いてraise <クラス名>, '<メッセージ>'
で発生させます。
raise ArgumentError, 'the first argument must be a string'
引数なしだとStandardErrorクラスを継承したRunTimeErrorになります。
例外処理は以下のように書きます。
begin X rescue E1 => e1 Y1 rescue E2 => e2 Y2 ensure Z end
Xの処理中に例外が発生し、それがE1クラスの例外ならY1の処理を、E2クラスの例外ならY2の処理を、どちらでもなかった場合はシステムエラーとなります。
Zの処理は例外が発生しなくてもいずれの場合も最後に実行されます。 (Zを定義できる意味はなんなのだろうか...。わからなかったので知っ てる人教えてください...)
ということで実装していきます。
準備
まずはproduction環境でもcacheしないようにしてアプリケーションを再起動させなくても変更を再読み込みするようにしておきます。
# config/environments/production.rb config.cache_classes = false
production環境で実行している場合はコンソールにログは出力されずに、log/production.log
に保存される。
500 Internal Sever Error
まず、500の例外処理を実装してみます。
例外を起こす
staff#indexが呼ばれたらかならずraiseするようにしてみます。
# app/controllers/staff/top_controller.rb class Staff::TopController < ApplicationController def index raise render action: 'index' end end
これでlocalhost:3000/staff
なんかにアクセスするとRails標準のエラーページが出ると思います。
例外処理を書く
そしたら例外処理を書いてみます。共通のcontrollerに以下のように書きます。
# app/controller/top_controller class ApplicationController < ActionController::Base ... rescue_from Exception, with: :rescue500 private ... def rescue500(e) @exception = e render 'errors/internal_server_error', status: 500 end end
rescue_from
はcontrollerの中で発生した例外を処理する。
ここではrescue500
メソッドを呼ぶように設定していて、rescure500
はexceptionオブジェクトを引数としてエラーページをレンダリングするような内容になっています。この場合はapp/views/errors/internal_server_error.erb
が標準では呼ばれます。
viewをつくる
さきほど指定したviewを作っていきます。
▶ vi app/views/errors/internal_server_error.slim
#error h1 500 Internal Server Error p We're very sorry for making a system error.
stylesheetは共通部分として作成します。
// app/assets/stylesheets/shared/errors.css.sass $dark_gray: #666666 $very_light_gray: #fafafa div#error width: 600px margin: 20px auto padding: 20px border-radius: 10px border: solid 4px $dark_gray background-color: $very_light_gray text-align: center p.url font-family: monospace
sharedディレクトリのスタイルシートもsprocketsの読み込み対象とします。
/* app/assets/stylesheets/staff.css */ ... *= require_tree ./shared ...
そしたらprecompileします。
$ bin/rake assets:precompile RAILS_ENV=production
そしてゲストOS側からサーバーを立ち上げて、localhost:3000/staffにアクセスしてみる...
さきほどデザインしたページが出てきて
We're very sorry for making a system error.
と表示されました!ナイス!!
流れまとめ
ということでここまでのエラー処理からエラー処理ページ作成までの流れをもう一度まとめておくと、
- controllerでraiseして例外を発生させる
- 共通のcontrollerで例外処理を行う振る舞いとそのメソッドを定義
- さっき作ったメソッドでrenderされるviewを作成
という感じで作ってきました。
次は403 Forbiddenつくっていきます!