【Rails7】動的なカスタムエラー画面を作成し、共通デザインを適用(400/401/403/404/429/500/503)

rails7-error
この記事は約4分で読めます。

はじめに

Railsアプリケーションは、エラーが発生した際にユーザーにフィードバックを提供するためのデフォルトエラーページをいくつか用意している。

ただ、ユーザーエクスペリエンスの観点から見ると、エラー文言、デザインに関してカスタマイズの余地があり、今回プロジェクトの開発でエラー画面のカスタマイズを行なったので、備忘録的にカスタムエラー画面の作成について記載。

カスタムエラーページの設定方法

静的/動的なエラーページの違い

Railsのエラーページはデフォルトでは、静的ファイルでpublicディレクトリに配置されている。publicディレクトリは、静的ファイル(画像、CSS、JavaScriptファイルなど)を格納するための場所であり、Railsアプリケーションが起動するサーバーから直接アクセスされるファイルが配置される。

静的なエラーページを設定する場合は、404(Not Found)、500(Internal Server Error)など、一般的なHTTPステータスコードに対応するカスタムエラーページを作成し、それぞれ404.html500.htmlといった名前でpublicディレクトリに保存する。

ただ、今回は静的なHTMLエラーページではなく、Railsのビューレンダリングシステムを利用した動的なエラーページを提供する場合で記載する。

動的なエラーページの設定方法

エラーハンドリングのコントローラを作成

まず、エラーページ用のコントローラを作成する。

Ruby
# app/controllers/errors_controller.rb

class ErrorsController < ApplicationController
  def not_found
    render(:status => 404)
  end

  def internal_server_error
    render(:status => 500)
  end
end

エラービューの作成

各エラーに対応するビューをapp/views/errorsディレクトリに作成する。例えば、404エラーと500エラーに対応するビューファイルは下記のようになる。

  • app/views/errors/not_found.html.erb
  • app/views/errors/internal_server_error.html.erb

ルーティングの設定

config/routes.rbファイルにエラーページへのルートを追加する。また、アプリケーションが存在しないルートにアクセスされた際に404エラーを表示するように設定することができる。

Ruby
# config/routes.rb

Rails.application.routes.draw do
  # 既存のルート定義

  # カスタムエラーページ用のルート
  get '/404', to: 'errors#not_found', as: :not_found
  get '/500', to: 'errors#internal_server_error', as: :internal_server_error

  # すべての未知のルートを404エラーページへリダイレクト
  match '*path', to: 'errors#not_found', via: :all
end

Application Configの設定

config/application.rbまたは環境固有の設定ファイル(例:config/environments/production.rb)で、カスタムエラーページを有効にする。この設定により、Railsはエラーページを動的に処理するためにアプリケーション自体のルーティングを使用する。

Ruby
# config/environments/production.rb
config.exceptions_app = self.routes

この段階で、例えば400errorの画面のerbファイルを下記のように作成していると、

Ruby
<p>
  不正なリクエストを検出しました。
</p>

下記のようにエラー画面が表示される。ただ、デザインを全く入れていないので、次にスタイルシートを適用していく。

スタイルシートの適用

app/views/layouts/error.html.erb: 共通エラーテンプレートを作成

app/views/layouts/配下に、error.html.erbというファイル名でエラーページの共通レイアウトファイルを作成する。このレイアウトファイルを使用することで、アプリケーション内で発生するさまざまなエラー(例えば、404 Not Found、500 Internal Server Errorなど)に対して、統一されたデザインを提供できる。

Ruby
# <strong>app/views/layouts/error.html.erb</strong>
<!DOCTYPE html>
<html>
<head>
  <title><%= content_for?(:title) ? yield(:title) : "ERROR" %></title>
  <!-- その他のメタタグやスタイルシートのリンク -->
</head>
<body>
  <!-- エラーメッセージやユーザーへの指示を含むページ固有のコンテンツ -->
  <%= yield %>
  
  <!-- 共通のナビゲーションリンクやフッター(オプション) -->
  <p class="top-page-link"><a href="/">ホームに戻る</a></p>
</body>
</html>

エラーページ専用のCSSファイルを作成

app/assets/stylesheetsディレクトリ(またはapp/javascript/stylesheetsディレクトリ、Rails 7以降でcssbundling-railsを使用している場合)に、エラーページ専用のスタイルシートファイルを作成する。今回は下記のように作成した。

Ruby
# app/assets/stylesheets/error.css
body {
  background-color: #fafafa;
  text-align: center;
}

.error-box {
  width: 90%;
  margin: 0 auto;
  padding-top: 36px;
}

.error-message {
  margin: 32px 0;
}
.error-box h1,
.error-box h3,
.error-message p {
  color: #737373;
}

.error-box h1 {
  font-size: 56px;
  margin-bottom: 0;
}

.error-box h3,
.error-message p {
  font-size: 18px;
  margin: 0;
}

.top-page-link {
  margin: 8px 0;
}

レイアウトでのスタイルシートの読み込み

エラーページ用のレイアウトファイル(app/views/layouts/error.html.erb)にstylesheet_link_tagヘルパーを使用して、作成したスタイルシートを読み込ませる。

application.sass.scssへのスタイルシートの統合

application.sass.scssファイルに、アプリケーション全体で使用するスタイルシートをインポートする。ここに今回作成したerror.cssも追加する。

Ruby
// app/assets/stylesheets/application.sass.scss
@import 'error.css';

プリコンパイルの管理

manifest.jsでは、静的アセット(画像やビルドされたファイルなど)をプリコンパイルの対象に含めている。

//= link_tree ../buildsにより、cssbundling-railsやその他ビルドツールによって生成されたapplication.cssを含む、ビルドされたアセットがプリコンパイルされる。

Ruby
//= link_tree ../images
//= link_tree ../builds

error.html.erbでのapplication.cssの利用

というわけで、エラーページのレイアウトであるerror.html.erbで、stylesheet_link_tag 'application'を使用して、application.cssを読み込ませる。これにより、エラーページにアプリケーション共通のスタイルが適用される。

Ruby
# <strong>app/views/layouts/error.html.erb</strong>
<!DOCTYPE html>
<html>
<head>
  <title><%= content_for?(:title) ? yield(:title) : "ERROR" %></title>
  <%= stylesheet_link_tag 'application', media: 'all' %>
  <!-- その他のメタタグやスタイルシートのリンク -->
</head>
<body>
  <!-- エラーメッセージやユーザーへの指示を含むページ固有のコンテンツ -->
  <%= yield %>
  
  <!-- 共通のナビゲーションリンクやフッター(オプション) -->
  <p class="top-page-link"><a href="/">ホームに戻る</a></p>
</body>
</html>

各種エラー文言と導線の設定

あとは、各種エラー文言を修正していく。

今回作成するエラー画面は、400/401/403/404/409/429/500/503の8画面。

適切な文言をChatGPTに聞いたところ、すぐに全てのエラー画面の文言候補を提示してくれた。

そのまま、コピペする感じで、例えば400 Bad Requestの場合は下記のように記載。

Ruby
<div class="error-box">
  <h1>400</h1>
  <h3>Bad Request</h3>
  <div class="error-message">
    <p>申し訳ありませんが、リクエストに誤りがあったため処理できませんでした。</p>
    <p>入力内容を確認して、もう一度お試しください。</p>
  </div>
</div>

エラー画面でのお問い合わせ/トップページに戻る/前の画面に戻るなどの導線に関しては悩ましいところ。そもそもこのようなエラー画面にユーザーが辿り着かないようにサービス設計することが理想で、ユーザーからのお問い合わせはできるだけ減らしたいのがサービス設計側の本音。

今回は、トップページに戻る、テキストリンクを添えるのでひとまず対応。

動的エラー画面をデザインのみ静的にQuickに検証したい場合

各種作成した動的エラー画面のデザインを確認したい場合、ローカル開発環境でエラーを意図的に発生させ、カスタムエラーページが正しく表示されるかテストする必要がある。

ただ、今回は意図的にエラーを発生させるのが手間なので、静的に確認したい。その場合は、エラーページ表示用のルーティングを追加する。

ルーティングの追加

config/routes.rbファイルに、開発環境専用のルーティングを追加する。これにより、/errors/:statusの形式のURLで任意のエラーページを表示できるようになる。

Ruby
# config/routes.rb
Rails.application.routes.draw do
  # 他のルーティング設定...

  # 開発環境でのみエラーページのプレビューを有効にする
  if Rails.env.development?
    get '/errors/:status', to: 'errors#show'
  end
end

エラーコントローラの作成

エラーページを表示するためのコントローラ(例:ErrorsController)を作成する。このコントローラでは、URLパラメータで指定されたステータスコードに対応するエラーページをレンダリングする。

Ruby
# app/controllers/errors_controller.rb
class ErrorsController < ApplicationController
  def show
    status_code = params[:status] || 500
    render template: "errors/#{status_code}", status: status_code, layout: 'error'
  end
end

上記の設定を行った後、ブラウザからhttp://localhost:3000/errors/404http://localhost:3000/errors/500など、任意のステータスコードに対応するURLにアクセスすることで、静的にエラーページを確認できる。これにより、実際にエラーを発生させることなく、エラーページのデザインやコンテンツをテストすることが可能になる。

実際に確認した結果の各種画面がこちら

無事、整合性が取れたデザインをエラー画面に適用できた。

コメント

タイトルとURLをコピーしました