カテゴリ: Rails 更新日: 2026/02/02

Railsでrescue_fromを使った例外処理の基本!初心者向けJSONレスポンスの書き方

rescue_fromで例外ハンドリング:404/422/500のJSONレスポンス設計
rescue_fromで例外ハンドリング:404/422/500のJSONレスポンス設計

先生と生徒の会話形式で理解しよう

生徒

「Railsでエラーが起きたときに、うまく処理する方法ってあるんですか?」

先生

「もちろんありますよ。rescue_fromという機能を使えば、予期しないエラーにも対応できます。」

生徒

「それって、具体的にどんなときに使うんですか?」

先生

「例えば、存在しないデータにアクセスしたときの404エラーや、無効なデータの422エラー、予期しないバグによる500エラーなどに対応できます。初心者でもできるように、わかりやすく説明しますね!」

1. Railsの例外処理とは?

1. Railsの例外処理とは?
1. Railsの例外処理とは?

Ruby on Rails(レイルズ)は、Webアプリケーション開発に使われる人気のフレームワークです。実際の開発では、エラー(例外)が発生することがあります。たとえば、存在しない記事を見ようとしたときや、データの保存に失敗したときなどです。例外処理(れいがいしょり)とは、こういったトラブルが発生したときに、アプリが止まらずに対応するしくみです。

Railsでは、rescue_from(レスキュー・フロム)という方法を使って、例外をキャッチし、エラーに対して適切なレスポンス(返答)を返すことができます。

2. rescue_fromの基本的な使い方

2. rescue_fromの基本的な使い方
2. rescue_fromの基本的な使い方

rescue_fromは、Railsのコントローラの中で使うメソッドです。特定の種類のエラーが起きたときに、別のメソッドを呼び出すことができます。これにより、エラー内容に応じて、ユーザーにわかりやすいエラーメッセージを返したり、ログを記録したりできます。

以下は、存在しないデータにアクセスしたときの「404エラー」をJSON形式で返す例です。


class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session

  rescue_from ActiveRecord::RecordNotFound, with: :render_404

  private

  def render_404(exception)
    render json: { error: 'データが見つかりませんでした。' }, status: :not_found
  end
end

3. よく使うステータスコード:404・422・500

3. よく使うステータスコード:404・422・500
3. よく使うステータスコード:404・422・500

例外に応じて、次のようなHTTPステータスコードを使い分けることが一般的です。

  • 404 Not Found:指定したデータが見つからないとき。
  • 422 Unprocessable Entity:バリデーションエラーなど、データが不正なとき。
  • 500 Internal Server Error:予期しないバグやサーバー側のエラー。

それぞれの例に対応したrescue_fromの書き方を見てみましょう。

4. 422エラーとバリデーションの例

4. 422エラーとバリデーションの例
4. 422エラーとバリデーションの例

ユーザーが送ってきたデータに問題があるとき、422エラーとして返すことができます。


class ApplicationController < ActionController::Base
  rescue_from ActiveRecord::RecordInvalid, with: :render_422

  private

  def render_422(exception)
    render json: { error: '入力内容が正しくありません。', details: exception.record.errors.full_messages }, status: :unprocessable_entity
  end
end

5. 500エラーのハンドリング例

5. 500エラーのハンドリング例
5. 500エラーのハンドリング例

コードのバグなどで、予想外のエラーが発生することがあります。このときは、500エラーとして処理します。ただし、開発中はそのままエラーを表示したほうが原因を特定しやすいため、本番環境だけに設定するのが一般的です。


class ApplicationController < ActionController::Base
  rescue_from StandardError, with: :render_500

  private

  def render_500(exception)
    logger.error exception.message
    logger.error exception.backtrace.join("\n")
    render json: { error: 'サーバー内部でエラーが発生しました。' }, status: :internal_server_error
  end
end

6. JSONレスポンスとは?

6. JSONレスポンスとは?
6. JSONレスポンスとは?

JSON(ジェイソン)とは、Webでよく使われるデータ形式の一つで、「{"name":"山田"}」のように鍵と値をセットで表します。スマートフォンアプリやJavaScriptとRailsを連携する際によく使われ、機械でも人間でも読みやすいのが特徴です。

今回のように、エラーの情報もJSONで返すことで、ユーザーにとっても開発者にとってもわかりやすくなります。

7. rescue_fromを複数使うときの注意点

7. rescue_fromを複数使うときの注意点
7. rescue_fromを複数使うときの注意点

rescue_fromは、どのエラーに対して、どのメソッドで処理するかを明示的に書く必要があります。同じ種類のエラーを複数回指定すると、後に書かれたものが優先されます。

また、StandardErrorはすべての例外の親にあたるため、先に記述すると他のエラーがキャッチされないことがあります。順番にも注意しましょう。

8. よくあるエラーとデバッグ方法

8. よくあるエラーとデバッグ方法
8. よくあるエラーとデバッグ方法

rescue_fromを設定したのに、うまく動かないことがあります。例えば:

  • 対象のエラークラスが違っている(例:RecordNotFoundと書くべきところをNotFoundにしている)
  • privateメソッドが呼び出せない場合
  • JSON形式が意図通りに出力されない

そんなときは、loggerを使ってエラーの中身をログに出すと、原因が分かりやすくなります。


def render_500(exception)
  logger.error exception.message
  logger.error exception.backtrace.join("\n")
  render json: { error: 'サーバーエラーが発生しました。' }, status: :internal_server_error
end

まとめ

まとめ
まとめ

Rails(レイルズ)における例外処理は、堅牢なWebアプリケーションやAPIを構築する上で欠かせない要素です。今回学習したrescue_fromは、コントローラ全体で共通のエラーハンドリングを可能にする非常に強力なツールです。これを使うことで、予期せぬエラーが発生してもアプリケーションがクラッシュすることなく、ユーザーに対して適切なメッセージや適切なHTTPステータスコード(404、422、500など)をJSON形式で返すことができます。

特にモダンなWeb開発においては、フロントエンド(ReactやVue.jsなど)やモバイルアプリと連携することが多いため、エラーが発生した際に「何が原因で失敗したのか」を機械的に判別しやすいJSON形式で伝えることが重要です。ActiveRecord::RecordNotFoundActiveRecord::RecordInvalidといったRails特有の例外を適切にキャッチし、共通のメソッド(render_404render_422など)に集約することで、コードの可読性とメンテナンス性が劇的に向上します。

実践的な実装例:データベース操作と例外処理

ここで、実際にデータベース(SQL)の操作とRailsのコードがどのように連動して例外を投げるのか、具体的なシミュレーションを見てみましょう。例えば、ユーザー情報を管理するusersテーブルがある場合を想定します。


id | name     | age | email
---+----------+-----+-----------------------
1  | 佐藤健一 | 28  | sato@example.com
2  | 鈴木愛   | 22  | suzuki@example.com
3  | 高橋裕二 | 35  | takahashi@example.com
4  | 田中花子 | 30  | tanaka@example.com
5  | 伊藤博   | 45  | ito@example.com

この状態で、存在しないID「99」を指定してデータを取得しようとするSQLが発行されたとします。


SELECT *
FROM users
WHERE id = 99;

このSQLの結果、レコードは見つかりません。RailsのUser.find(99)というメソッドはこの時にActiveRecord::RecordNotFoundという例外を発生させます。これをrescue_fromで処理しない場合、ユーザーには無機質なエラー画面が表示されてしまいますが、適切に設定していれば以下のようなJSONレスポンスを返すことができます。


{
  "status": 404,
  "error": "Not Found",
  "message": "指定されたユーザー(ID: 99)は見つかりませんでした。"
}

バリデーションエラー(422)の具体例

次に、データの更新時にバリデーション(入力チェック)に引っかかった場合を考えます。メールアドレスが空ではいけないというルールがある場合、以下のようなSQLが実行されようとしますが、Rails側でエラーを検知します。


# Rails側での更新処理の例
begin
  user = User.find(1)
  user.update!(email: "") # ここでバリデーションエラーが発生
rescue ActiveRecord::RecordInvalid => e
  # rescue_fromを使っている場合は、自動的にrender_422などが呼ばれる
end

このとき、データベースの中身は変更されず、以下のような状態が維持されます。


id | name     | age | email
---+----------+-----+-----------------------
1  | 佐藤健一 | 28  | sato@example.com
2  | 鈴木愛   | 22  | suzuki@example.com
3  | 高橋裕二 | 35  | takahashi@example.com
4  | 田中花子 | 30  | tanaka@example.com
5  | 伊藤博   | 45  | ito@example.com

そして、クライアント側には以下のような詳細なエラー内容が返却されます。


{
  "error": "入力内容が正しくありません。",
  "details": [
    "メールアドレスを入力してください",
    "メールアドレスは不正な形式です"
  ]
}

本番環境での運用上の注意

rescue_from StandardErrorを使用して500エラーをキャッチする際は注意が必要です。開発環境(development)でこれを行ってしまうと、エラーのスタックトレース(どこでエラーが起きたかの詳細)が隠されてしまい、デバッグが非常に困難になります。そのため、以下のように条件分岐を行うか、本番環境の設定ファイルで制御するのがプロのやり方です。


class ApplicationController < ActionController::Base
  # 本番環境のみ、予期せぬエラーを共通の500エラー画面にする
  if Rails.env.production?
    rescue_from StandardError, with: :render_500
  end

  private

  def render_500(e)
    # ログには詳細を記録し、ユーザーには簡潔なメッセージを出す
    ExceptionNotifier.notify_exception(e) # 通知サービスなどを使う例
    render json: { error: "システムエラーが発生しました。時間をおいて再度お試しください。" }, status: 500
  end
end

例外処理をマスターすることは、単に「エラーを隠す」ことではありません。エラーが起きたときに「何が起きたのかを正しく伝え、システムの安定性を保つ」ための技術です。Railsが提供するrescue_fromを使いこなし、ユーザーにとっても開発者にとっても優しいアプリケーションを目指しましょう。

先生と生徒の振り返り会話

生徒

「先生、rescue_fromの実装方法がすごくよく分かりました!これって、すべてのエラーをStandardErrorで一つにまとめちゃダメなんですか?」

先生

「いい質問ですね。結論から言うと、おすすめしません。なぜなら、エラーの原因によってユーザーが取るべき行動が変わるからです。例えば、404エラーなら『別のURLを探す』、422エラーなら『入力内容を修正する』といった具合です。全部500エラーで返してしまうと、ユーザーはどうしていいか分からなくなってしまいますよ。」

生徒

「なるほど。だからエラーごとにメソッドを分けて、適切なステータスコードを返す必要があるんですね。コードの書く順番も大事って記事にありましたが、それはどうしてですか?」

先生

「Railsはrescue_from下から上に向かって判定していく性質があるんです。だから、より具体的なエラー(RecordNotFoundなど)を下に、抽象的なエラー(StandardErrorなど)を上に書くのが基本です。逆にしてしまうと、すべてのエラーがStandardErrorに吸い込まれてしまうんですよ。」

生徒

「危ないところでした!下から上に判定されるのは意外ですね。あと、JSONでエラーを返すときにdetailsとかで配列を渡すのも、フロントエンドの人からすると親切ですよね。」

先生

「その通りです!Railsのバリデーションエラーメッセージをそのまま配列で渡してあげれば、フロントエンド側でループ処理してエラー表示を出すのが楽になります。開発チーム全体の効率も上がるので、ぜひ意識してみてください。次は実際にAPIを叩いて、意図した通りのJSONが返ってくるかテストしてみましょうか。」

生徒

「はい!Postmanやcurlを使って、エラーレスポンスが正しく返ってくるか試してみます!」

関連記事:
カテゴリの一覧へ
新着記事
New1
Ruby
“すべてはオブジェクト”を体感!初心者向けRubyのオブジェクト指向入門【irbで学ぶ】
New2
Ruby
Rubyの標準入出力を完全ガイド!puts・print・pの違いとデバッグ活用法
New3
Ruby
Gemとは?RubyGemsとBundlerを初心者向けに完全解説!依存関係管理も図解でわかりやすく理解
New4
Ruby
Rubyの文字エンコーディング入門!UTF-8・マジックコメント・外部/内部エンコーディングを完全解説
人気記事
No.1
Java&Spring記事人気No1
Ruby
Rubyのreduceとinject入門!合計計算や集計を初心者向けに分かりやすく解説
No.2
Java&Spring記事人気No2
Ruby
Rubyの文字列エンコーディング完全ガイド!Encoding・force_encoding・encodeを初心者向け解説
No.3
Java&Spring記事人気No3
Ruby
Rubyの始め方ガイド:インストールから最初のHello Worldまで(Windows/Mac/Linux)
No.4
Java&Spring記事人気No4
データベース
PostgreSQLのWHERE句を徹底解説!初心者でもわかるSQLデータ抽出の基本
No.5
Java&Spring記事人気No5
Ruby
Rubyのfind/detect/find_indexを徹底解説!目的のデータを素早く探す方法
No.6
Java&Spring記事人気No6
Ruby
Rubyで比較演算子を完全解説!==・===・<=>・eql? の使い分け
No.7
Java&Spring記事人気No7
Ruby
Rubyのselect/reject/filterの使い方を完全解説!初心者向けの条件抽出レシピ
No.8
Java&Spring記事人気No8
データベース
PostgreSQLで順位付け!ROW_NUMBER関数の使い方を初心者向けに徹底解説