エラーページを自前のものにしたいとき、これまではごく簡単に、public/500.htmlとかを書き換えてました。
ただ、これだと、imgタグとかを使ったときにRoutingErrorが発生したり、
動的になにかを表示できないと。
で、Render系メソッド呼び出してエラーページをレンダリングしたくなるわけです。
で、ググってみた。
すると、ActionController::Rescue::rescue_actionをオーバーライドするといいよ~
等の情報が。
でも、rescue_actionをオーバーライドすると、
ログなんかも自前で呼び出さないといけなくなるとか。
あ~、結構めんどくさいなあ・・・と思いつつドキュメントとか、ソースを読んでみると、
どうやらrescue_action_in_publicをオーバーライドすればいいらしい。
エラー発生から画面表示までの流れは、
エラー発生->
rescue_action->
エラーハンドラ呼び出し/アクセスもと判別->
(ローカルアクセスの時)rescue_action_locally(開発中のいつものエラー画面)
(パブリックアクセスの時)rescue_action_in_public->
エラーコード取得->エラー画面表示(render :file)
という感じ。
rescue_actionを単純にオーバーライドすると、
・ハンドラ呼び出しがされない
- ロガー呼び出しがない
・アクセスもと判別がない
- ローカル開発中のエラートラッカーが見られない
等々の問題が。
(もちろん、オーバーライド先で実装すればいい話だけど)
それよりは、もっと末端の
rescue_action_in_publicをオーバーライドすれば、
実際にサービスアクセスされたときだけオリジナルのエラー画面を表示できるし、
ロガー関連もデフォルトのものが自動的に呼び出されるので、
これまでにロガー関係に手を入れていた場合もそのままいける。
ちゅう訳で、
自前エラー画面を実装するときはActionController::Rescue::rescue_action_in_publicをオーバーライドしよう。
ちなみに自分でやったのは、ActionControllerでオーバーライド。
def rescue_action_in_public(exception)
code = response_code_for_rescue(exception).to_i
render_page = 'normal_error' # 500番台を基本とする
if code >= 400 && code < 500 # 400番台のエラー
render_page = 'no_route'
end
puts render_page
puts "xhr request is #{request.xhr?}"
if request.xhr?
render :partial=>"#{render_page}"
else
render :action=>"#{render_page}", :layout=>'error'
end
end
と、こんな感じ。
よく見ると、ドキュメントにも書いてある。
rescue_action_in_public(exception)
Overwrite to implement public exception handling (for requests answering false to local_request?). By default will call render_optional_error_file. Override this method to provide more user friendly error messages.
※Rails1.2系です。2.0系はもっと便利になってるらしい。