Edited at

Railsでエラーページを動的に

More than 3 years have passed since last update.

適当なactionを用意してexceptions_appを変更すると、public/404.htmlなどの挙動を変えられます。


サンプルコード


config/application.rb

class MyApp::Application < Rails::Application

config.exceptions_app = routes
end


config/routes.rb

MyApp.application.routes.draw do

match '/404' => 'errors#show', id: 404, via: :all
match '/422' => 'errors#show', id: 422, via: :all
match '/500' => 'errors#show', id: 500, via: :all
end


app/controllers/errors_controller.rb

class ErrorsController < ApplicationController

end


app/views/errors/show.html.erb

<%# params[:id]とかを使って適当なエラー用のコンテンツを描画する %>



説明


rack middleware stack

Railsのデフォルトのrack middleware stackには、ActionDispatch::DebugExceptionsとActionDispatch::ShowExceptionsが含まれています。これは rake middleware を実行することで確かめられます。これらはdevelopment環境、production環境に関わらず含まれていますが、Rails.configurationにより挙動が異なります。


ActionDispatch::Journey::Router

config/routes.rb で定義したルーティングは、内部ではActionDispatch::Journey::Routerというライブラリによって処理されます。このRouterもRack middlewareになっています。もしこのRouterが適切なルーティングを見つけられなかった場合、[404, {'X-Cascade' => 'pass'}, ['Not Found']] というレスポンスが返ります。


ActionDispatch::DebugExceptions

ActionDispatch::Journey::Routerの外側にはActionDispatch::DebugExceptionsが居ます。もし X-Cascade: pass というレスポンスヘッダが返ってきた場合、production環境ではActionController::RoutingErrorをraiseし、development環境ではエラーの内容を表示するHTMLを返します。この環境による違いは、Rails.configuration.consider_all_requests_localを変更することで変更できます。もしdevelopment環境でもproduction環境同様のエラー表示を試したい場合は、この値をfalseにすると良いでしょう。


ActionDispatch::ShowExceptions

DebugExceptionsの外側にはActionDispatch::ShowExceptionsが居ます。ShowExceptionsは、内側のRackアプリで例外が発生した場合、env["PATH_INFO"] (※URLのパスを示す情報) を /404 などの対応するステータスコードを表す値に書き換えた上で、Rails.configuration.exceptions_appにリクエストの処理を委譲します。


ActionDispatch::ExceptionWrapper

「ActionController::RoutingErrorの例外に対応するステータスコードは404である」といった情報は、ActionDispatch::ExceptionWrapperが管理しています。この対応表はRails.configuration.action_dispatch.rescue_responsesと紐付いており、例えばActiveRecordはRailsアプリ初期化時にこの対応表にActiveRecord::RecordNotFoundを404として扱うように追加したりしています。


ActionDispatch::PublicExceptions

Rails.configuration.exceptions_appはデフォルトの状態ではActionDispatch::PublicExceptionsが設定されています。このrack applicationは、/404に対してpublic/404.htmlを返却するような動作をします。エラー時の挙動を変えたい場合は、Rails.configuration.exceptions_appを別のrack applicationに変更すれば良いわけです。


参考リンク :link: