Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Railsのエラーページをカスタマイズする(翻訳)

概要
原著者の許諾を得て翻訳・公開いたします。

Railsのエラーページをカスタマイズする(翻訳)

本記事は、私の著書『The Rails and Hotwire Codex』から抜粋して手を加えたものです。

Railsで何らかの問題が発生したときに表示されるデフォルトのエラーページは、かなり退屈です。

デフォルトのRails 404エラーページ

このエラーページは/publicフォルダ内に保存されていて、Railsスタックによってレンダリングされません。

このエラーページの見た目をもう少し麗しくしたいので、Railsインフラストラクチャを使ってエラーをレンダリングするためのコントローラーを作成することにします。

🔗 セットアップ

例外やスタックトレースの代わりに、一般公開したいエラーをレンダリングするために、Railsのdevelopmentモードでconsider_all_requests_local設定を以下のように変更する必要があります。

# config/environments/development.rb
require "active_support/core_ext/integer/time"

Rails.application.configure do
  # ...

  config.consider_all_requests_local = false
end

次に、以下を実行してコントローラを作成します。

$ bin/rails g controller errors --no-helper --no-test-framework

このコントローラにあるのはshowアクションだけです。このアクションは、発生した例外のエラーコードを抽出し、適切なビューをレンダリングします。エラーコード 403404500については専用のエラーページを用意し、それ以外のエラーについて404ページにフォールバックすることにします。

class ErrorsController < ApplicationController
  layout "error"

  def show
    @exception = request.env["action_dispatch.exception"]
    @status_code = @exception.try(:status_code) ||
                   ActionDispatch::ExceptionWrapper.new(
                    request.env, @exception
                  ).status_code

    render view_for_code(@status_code), status: @status_code
  end

  private
    def view_for_code(code)
      supported_error_codes.fetch(code, "404")
    end

    def supported_error_codes
      {
        403 => "403",
        404 => "404",
        500 => "500"
      }
    end
end

上のコードを見ると、layout "error"でエラー用のカスタム"error"レイアウトを使っていることもわかります。このカスタムレイアウトでは、通常のアプリケーションレイアウトの要素は不要なので、シンプルなものにします。

以下を実行して新しいエラーレイアウトを作成します。

$ touch app/views/layouts/error.html.erb
<%# app/views/layouts/error.html.erb %>

<!DOCTYPE html>
<html>
  <head>
    <%= render "layouts/head" %>
  </head>

  <body>
    <main>
      <%= yield %>
    </main>
  </body>
</html>

ビューを作成して、好みのスタイルでエラーページを作成します。

$ touch app/views/errors/403.html.erb
$ touch app/views/errors/404.html.erb
$ touch app/views/errors/500.html.erb

次は、エラー時にこのコントローラが使われるようRailsに指示する必要があります。

🔗 exceptions_app

Railsには、カスタムエラーをレンダリングするためのフックがあり、これはexceptions_appというプロパティで設定できます。このプロパティには、例外が発生したときに呼び出されるRackアプリを割り当てる必要があります。

Railsのあらゆるコントローラアクションは、実際には独自のRackアプリケーションです。Rackエンドポイントは、コントローラクラスのactionメソッドによって返されます。

# ...

module MyApp
  class Application < Rails::Application
    config.load_defaults 7.0

    config.exceptions_app = ->(env) {
      ErrorsController.action(:show).call(env)
    }
  end
end

サーバーを再起動して、存在しないページにアクセスしてみましょう(コントローラアクションで手動でエラーをトリガーしても構いません)。カスタムエラーページが実際に表示されることがわかります。

お知らせ

本記事を気に入っていただけたら、ぜひ私の著書『The Rails and Hotwire Codex』を読んでRailsとHotwireのスキルをアップしてください。

関連記事

Rackによるクエリ文字列のパースの実装を調査してみた


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。