はじめに
Railsアプリケーションは、エラーが発生した際にユーザーにフィードバックを提供するためのデフォルトエラーページをいくつか用意している。
ただ、ユーザーエクスペリエンスの観点から見ると、エラー文言、デザインに関してカスタマイズの余地があり、今回プロジェクトの開発でエラー画面のカスタマイズを行なったので、備忘録的にカスタムエラー画面の作成について記載。
カスタムエラーページの設定方法
静的/動的なエラーページの違い
Railsのエラーページはデフォルトでは、静的ファイルでpublicディレクトリに配置されている。publicディレクトリは、静的ファイル(画像、CSS、JavaScriptファイルなど)を格納するための場所であり、Railsアプリケーションが起動するサーバーから直接アクセスされるファイルが配置される。
静的なエラーページを設定する場合は、404(Not Found)、500(Internal Server Error)など、一般的なHTTPステータスコードに対応するカスタムエラーページを作成し、それぞれ404.html、500.htmlといった名前でpublicディレクトリに保存する。
ただ、今回は静的なHTMLエラーページではなく、Railsのビューレンダリングシステムを利用した動的なエラーページを提供する場合で記載する。
動的なエラーページの設定方法
エラーハンドリングのコントローラを作成
まず、エラーページ用のコントローラを作成する。
# 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エラーを表示するように設定することができる。
# 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はエラーページを動的に処理するためにアプリケーション自体のルーティングを使用する。
# config/environments/production.rb
config.exceptions_app = self.routesこの段階で、例えば400errorの画面のerbファイルを下記のように作成していると、
<p>
  不正なリクエストを検出しました。
</p>下記のようにエラー画面が表示される。ただ、デザインを全く入れていないので、次にスタイルシートを適用していく。

スタイルシートの適用
app/views/layouts/error.html.erb: 共通エラーテンプレートを作成
app/views/layouts/配下に、error.html.erbというファイル名でエラーページの共通レイアウトファイルを作成する。このレイアウトファイルを使用することで、アプリケーション内で発生するさまざまなエラー(例えば、404 Not Found、500 Internal Server Errorなど)に対して、統一されたデザインを提供できる。
# <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を使用している場合)に、エラーページ専用のスタイルシートファイルを作成する。今回は下記のように作成した。
# 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も追加する。
// app/assets/stylesheets/application.sass.scss
@import 'error.css';プリコンパイルの管理
manifest.jsでは、静的アセット(画像やビルドされたファイルなど)をプリコンパイルの対象に含めている。
//= link_tree ../buildsにより、cssbundling-railsやその他ビルドツールによって生成されたapplication.cssを含む、ビルドされたアセットがプリコンパイルされる。
//= link_tree ../images
//= link_tree ../buildserror.html.erbでのapplication.cssの利用
というわけで、エラーページのレイアウトであるerror.html.erbで、stylesheet_link_tag 'application'を使用して、application.cssを読み込ませる。これにより、エラーページにアプリケーション共通のスタイルが適用される。
# <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の場合は下記のように記載。
<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で任意のエラーページを表示できるようになる。
# config/routes.rb
Rails.application.routes.draw do
  # 他のルーティング設定...
  # 開発環境でのみエラーページのプレビューを有効にする
  if Rails.env.development?
    get '/errors/:status', to: 'errors#show'
  end
end
エラーコントローラの作成
エラーページを表示するためのコントローラ(例:ErrorsController)を作成する。このコントローラでは、URLパラメータで指定されたステータスコードに対応するエラーページをレンダリングする。
# 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/404、http://localhost:3000/errors/500など、任意のステータスコードに対応するURLにアクセスすることで、静的にエラーページを確認できる。これにより、実際にエラーを発生させることなく、エラーページのデザインやコンテンツをテストすることが可能になる。
実際に確認した結果の各種画面がこちら








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



コメント