はじめに
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 ../builds
error.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にアクセスすることで、静的にエラーページを確認できる。これにより、実際にエラーを発生させることなく、エラーページのデザインやコンテンツをテストすることが可能になる。
実際に確認した結果の各種画面がこちら
無事、整合性が取れたデザインをエラー画面に適用できた。
コメント