【動的VS静的】Railsの404/500エラーページ 静的の勝利
揉めに揉める議論
最初、もりじゅんさんの以下の記事を参考にさせていただこうとしたのですが、
Qiitaでも(多分もりじゅんさんの記事を参考にした)同じ例をみかけて、そこでyuki24さんが、この方法はあまりよい方法でないというコメントをしてました。
Railsの404,500エラーページをカスタマイズ - Qiita
このコメントでひと記事できてしまうやつ。。笑
必読です。。
ということでApplicationControllerに例外ハンドラを書いてそれに応じてrenderするtemplateを振り分ける、という方法はできれば避けたいですね。
Rails覚えたての頃は、そちらの方法で実装していました。
実際に最初に静的ページで実装してみると、もともとRailsで用意されているpublic/hoge.html
を使うことになるとは思いますが、エラーページにナビゲーションバーやフッターを追加してその内容が変わっていくのであれば、あまり賢くないように思います。いちいち変更するのはとても面倒そうです。
そこでRailsにconfig.exceptions_app
という設定があり、それをうまく使うことでエラー処理を行うことが出来るのでそれを使おう、ということになります。
rambulanceを試してみる
この方法を用いている、yuki24さんが作られているgemを使いながらこの方法についてみていきたい。
まずはgemを追加してbundle install
# Gemfile gem 'rambulance'
$ bundle install
そしたらranbulance:installでファイルのテンプレートを生成します。-e
オプションで特定のテンプレートエンジンを指定できます。
$ rails g rambulance:install -e slim
Railsではproductionで動かしてもアドレスがlocalhost
や127.0.0.1
だと本番用のエラーページを出してくれません。ranbulanceはその辺も対応してくださってます。素敵すぎる。。
以下の様なURLでエラーページにアクセスすることができます。
localhost:3000/rambulance/***
ここまで使い進めてやはりつまずいたのは、exceptions_app
を用いているというところ。。
exceptions_app
は3.2から追加された機能で、例外発生時に呼ばれる例外処理アプリケーションを設定するというもの。デフォルトではActionDispatch::PublicExceptions.new(Rails.public_path)
が使用される。Release Noteからは以下。
Added config.exceptions_app to set the exceptions application invoked by the ShowException middleware when an exception happens. Defaults to ActionDispatch::PublicExceptions.new(Rails.public_path).
参考: Railsのエラーハンドリング - 一分一秒真剣勝負!
こいつでRails標準のActionDispatch::PublicExceptionsを独自のコントローラに差し替えることができます。
middlewareレベルでExceptionsをrescueするActionDispatch::PublicExceptionsクラスのコードは以下。読むととても勉強になります。
rails/show_exceptions.rb at f49d20ef36c2d339e7a988fdc52981cdb95af22f · rails/rails · GitHub
ですが、例外が発生した場合はApplicationControllerまで届かずActionDispach::PublicExceptionsにrescueされてそちらのcontrollerに処理が委託されるので、ApplicationControllerで定義しているインスタンスメソッドやincludeしているApplicationHelperなどのヘルパーメソッドは使えなくなってしまう。
僕の場合はspのviewのlayout切り替えをここで行っていたりstylesheetの読み込み用のメソッドを用意したりしていたので結構つらみがあった。
やっぱり動的にやるのきつい。。
yuki24さんもおっしゃるように、よほど動的にしないといけないケース以外では静的ページとしてエラーページを用意する方が今のところよさそうかなと思いました。。結局メンテナンスのときなど、HTTPサーバーのレイヤーからエラーを出さなければいけないときは別途対応が必要ですし。
この方の記事も読んでおくとRailsでのエラー処理の考えが深まります。。
雑に学んだことをまとめると、ApplicationControllerで拾った例外でview振り分けるのでは(ActionController::RoutingError は ApplicationControllerに到達する前に例外が発生しているので)見た目の解決にしかなってないのでよくなくて、やるならActionDispatch::PublicExceptionsで委託するcontrollerを変えないといけないのだけど、それだとApplicationController経由しないから色々つらいよ、みたいな感じ。。。
yuki24さんの結論は「そこまでして動的にやる意味あるんですかね?」とのこと。。。w
つらい
ということで結局静的ページでやることにしました。つらい