ゴールのイメージ
本番環境で 500がカスタムページになる
Rails のデフォルト public/500.html は使わない
app/views/errors/error500.html.slim が本物の 500 エラーでも出る
デザイン用の記事の時と何が違うの?
Railsで500エラーページをとりあえず表示させる方法(デザイン作成用)
| 項目 | 上記の記事(開発用) | この記事(本番用 exceptions_app) |
|---|---|---|
| 目的 | デザイン確認 | 本物のエラーを差し替える |
| URL | /500 にアクセスしたときだけ | 404/500/422 が実際に発生したとき |
| 仕組み | ただのルーティング | Rails の例外処理を乗っ取る |
| 本番で動く? | 動かない | 動く |
| 404/500/422 の区別 | できない | できる |
| public/500.html | 使われる | 使われない |
| 必要な設定 | ルート1行だけ | exceptions_app + ルート + コントローラ |
Rails に「エラー時は routes.rb を通せ」と指示する
ファイル:config/application.rb
class Application < Rails::Application の中にこれを追加
config.exceptions_app = self.routes
解説
Rails は本来、エラーが起きると public/404.html や public/500.html を直接返すらしい。
でもこの設定を入れると
「エラーが起きたら routes.rb に投げてね」
と Rails に教えることになる
これが本番用エラー処理の最重要ポイント!
routes.rb に 404 / 500 を定義する
ファイル:config/routes.rb
Rails.application.routes.draw do
# 本番用エラー処理
get "/404", to: "errors#error404"
get "/500", to: "errors#error500" # ←今回はここだけ
get "/422", to: "errors#error422"
end
ポイント
404 → ページが見つからない
500 → サーバー内部エラー
422 → バリデーションエラーなど
ここは前回のデザイン用で設定してたのでそのままでOK.
ErrorsController を作る
ファイル:app/controllers/errors_controller.rb
class ErrorsController < ApplicationController
layout false # ← application.html.slim を使いたくない場合はこれ
def error404
render "errors/error404", status: 404
end
def error500
render "errors/error500", status: 500 # ←今回はここだけ
end
def error422
render "errors/error422", status: 422
end
end
補足
layout false は「レイアウト使わない」設定
application レイアウトを使いたいなら消してOK
ここも前回のデザイン用で設定してたのでそのままでOK.
ErrorsController を作る
ファイル:app/controllers/errors_controller.rb
class ErrorsController < ApplicationController
layout false # レイアウトを使いたくない場合
def error404
render "errors/error404", status: 404
end
def error500
render "errors/error500", status: 500
end
def error422
render "errors/error422", status: 422
end
end
ここもデザイン用の時に作ってるからそのままでOK
ビューを作る
doctype html
html
head
meta charset="utf-8"
title エラーが発生しました
body
div
p 申し訳ありません。サーバー内部でエラーが発生しました。
p 時間をおいて再度アクセスしてください。
= link_to "トップページへ戻る", root_path
ここもデザイン確認用に作った 500 ページをそのまま使える。
とりあえずシンプルに参考コードを置いておきます。
本番モードで動作確認する
ローカルで本番モードを起動:
RAILS_ENV=production rails assets:precompile
RAILS_ENV=production rails s
404 の確認
存在しない URL にアクセス
→ error404.html.slim が出る
500 の確認
コントローラの中で「わざと例外を起こす」
Rails では、例外(エラー)が発生すると 500 エラーになる。
だから、どこかのコントローラのアクションに 1行だけ 追加する。
例:UsersController の index に書く
def index
raise "test error"
end
ブラウザでアクセスする
http://localhost:3000/users
これだけ。
これがどう動くの?
・ブラウザで /users にアクセスする
・Rails が index アクションを実行する
・raise "test error" が実行される
・Rails が「例外が起きた!」と判断
・500 Internal Server Error が発生
・config.exceptions_app = self.routes により
→ Rails は routes.rb に処理を投げる
・/500 のルートが呼ばれる
・ErrorsController#error500 が実行される
・error500.html.slim が表示される
つまり、
本物の500エラーが発生したときの流れを完全に再現できる。