Rails「ActiveRecord::RecordNotFound」エラーの原因と対処法|404ハンドリングと例外設計
Ruby on Rails 開発で頻発するエラー:
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=999)
ActiveRecord::RecordNotFound (Couldn't find Post with [WHERE "posts"."slug" = $1])
ActiveRecord::RecordNotFound: Couldn't find all Articles with 'id': (1, 2, 3) (found 2 results, but was looking for 3)
ActiveRecord::RecordNotFound は「指定したレコードが見つからない」場合に発生する例外。find メソッドの仕様通りの動作ですが、
- 開発中に頻発してログが煩い
- API で 500 エラーを返してしまう
- 「404 Not Found」を返したいのに 500 になる
- カスタムエラーページが表示されない
- N+1で大量に出ることがある
- find_by! と find はどちらを使うべき?
など、設計判断に迷うポイントが多くあります。
本記事では、ActiveRecord::RecordNotFound のすべての原因と対処法を、現場で即使えるパターンとして整理します。エラーの本質、find系メソッドの違い、rescue_from による404ハンドリング、API・JSONレスポンスでのカスタマイズ、関連エラー、デバッグ手法、FAQまで完全網羅。この1本でRails 404 ハンドリングをマスターできます。
- 1. 結論:今すぐ試すべき3ステップ
- 2. まず押さえる:エラーの本質
- 3. find系メソッドの完全比較
- 4. 発生パターン別の対処
- 5. rescue_from による404ハンドリング
- 6. ローカルコントローラ内での rescue
- 7. APIモードでのカスタマイズ
- 8. 404ページのカスタマイズ
- 9. 関連メソッドの活用
- 10. DB index と RecordNotFound パフォーマンス
- 11. ログの読み方とデバッグ
- 12. ベストプラクティス
- 13. トラブルシューティング
- 14. 関連エラーとの違い
- 15. よくある質問(FAQ)
- 15.1. Q1. find と find_by はどちらを使うべきですか?
- 15.2. Q2. 404 にカスタム HTML を返したい
- 15.3. Q3. API でカスタム JSON を返したい
- 15.4. Q4. テストで RecordNotFound を確認する方法
- 15.5. Q5. RecordNotFound を意図的に発生させる方法
- 15.6. Q6. 404 のログを抑制したい
- 15.7. Q7. find のN+1問題はありますか?
- 15.8. Q8. routes でidが文字列だと?
- 15.9. Q9. 404 でリダイレクトすべき?
- 15.10. Q10. find の前にバリデーションすべき?
- 15.11. Q11. SoftDelete を使っている場合
- 15.12. Q12. UUID をPKに使う場合
- 16. 参考リンク・関連資料
- 17. まとめ
結論:今すぐ試すべき3ステップ
時間がない方向けに、まず実施すべき手順を示します。
ステップ1:発生原因を特定
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=999)
↑ ↑
モデル 検索条件
スタックトレースから発生位置確認:
app/controllers/users_controller.rb:8:in `show'
ステップ2:意図通りなら 404 として処理
find でレコードが見つからないのは自然。Rails では標準で 404 を返す:
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
# 見つからなければ自動的に 404 ページ
end
end
開発環境では例外画面が出ますが、本番では public/404.html が表示。
ステップ3:カスタマイズしたい場合
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound do |exception|
render json: { error: exception.message }, status: :not_found
# または
# render template: "errors/not_found", status: :not_found
end
end
詳細は以下で解説します。
まず押さえる:エラーの本質
ActiveRecord::RecordNotFound とは
ActiveRecord の find 系メソッドが該当レコードを発見できなかった時に発生する例外です。
User.find(999)
# => ActiveRecord::RecordNotFound (Couldn't find User with 'id'=999)
Rails の自動404変換
ApplicationController のデフォルト動作として、Rails は以下の例外を自動的にHTTPステータスコードにマッピングします:
# rails/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
ActionDispatch::ExceptionWrapper.rescue_responses
# => {
# "ActiveRecord::RecordNotFound" => :not_found,
# "ActionController::RoutingError" => :not_found,
# "ActionController::UnknownController" => :not_found,
# "ActionController::BadRequest" => :bad_request,
# "ActionController::ParameterMissing" => :bad_request,
# ...
# }
つまり、ActiveRecord::RecordNotFound は本番環境では自動的に404になります。開発環境では例外画面が出るだけ。
開発環境 vs 本番環境
| 環境 | RecordNotFound の挙動 |
|---|---|
| development | エラー画面(スタックトレース表示) |
| test | テストが失敗(例外を rescue しない場合) |
| production | 自動的に 404 ページを表示 |
config/environments/production.rb の以下の設定で制御:
config.consider_all_requests_local = false # false なら本番モードで404に
なぜエラーで困るのか
問題なケース:
- 意図しない場所で発生: 検索処理途中など
- APIで500を返す: JSON APIで404を返すべき場面
- ログが大量: ボット等が無効URLを叩くと記録される
- UX悪化: デフォルト404ページが汎用的すぎる
find系メソッドの完全比較
ActiveRecord::RecordNotFound を理解するには、find 系の挙動を把握することが重要。
find(最頻出)
User.find(1)
# => レコードあれば返す
# => 無ければ RecordNotFound 例外
User.find(1, 2, 3)
# => 3件全部見つかればArray
# => 1件でも見つからなければ RecordNotFound
find_by(nil返却)
User.find_by(email: "alice@example.com")
# => レコードあれば返す
# => 無ければ nil
find_by!(例外)
User.find_by!(email: "alice@example.com")
# => レコードあれば返す
# => 無ければ RecordNotFound
first / last
User.first # => 最初のレコード or nil
User.last # => 最後のレコード or nil
first! / last!(例外)
User.first! # => レコードあれば返す、無ければ RecordNotFound
User.last! # => 同上
where().first
User.where(active: true).first
# => 条件マッチの最初 or nil
User.where(active: true).first!
# => マッチなしなら RecordNotFound
take / take!
User.take # => 任意の1件 or nil
User.take! # => 任意の1件 or RecordNotFound(無ければ)
sole / find_sole_by(Rails 7+)
User.where(email: "alice@example.com").sole
# => 厳密に1件だけ
# => 0件: RecordNotFound
# => 2件以上: ActiveRecord::SoleRecordExceeded
完全比較表
| メソッド | 引数 | 見つかった | 見つからない |
|---|---|---|---|
find(id) | id(PK) | レコード | RecordNotFound |
find(ids) | 配列 | レコード配列 | RecordNotFound(1件でも不足) |
find_by(...) | 条件 | レコード | nil |
find_by!(...) | 条件 | レコード | RecordNotFound |
first / last | なし | レコード | nil |
first! / last! | なし | レコード | RecordNotFound |
take | なし | レコード | nil |
take! | なし | レコード | RecordNotFound |
sole | なし | レコード(厳密1件) | RecordNotFound / SoleRecordExceeded |
使い分け指針
# 1. URLパラメータから検索 → find(404が自然)
def show
@user = User.find(params[:id])
end
# 2. 任意条件検索(不在も正常) → find_by
def signup
if User.find_by(email: params[:email])
redirect_to login_path, alert: "既に登録済み"
end
end
# 3. 必須レコードの取得 → find_by!
def admin
@admin = User.find_by!(role: "admin")
end
# 4. 最初の1件取得 → first / first!
@latest = Article.order(created_at: :desc).first
発生パターン別の対処
パターン1:URLからの不正なID
def show
@user = User.find(params[:id]) # 999 みたいな存在しないID
end
対処: 自動 404 で問題なし。カスタマイズしたい場合は rescue_from。
パターン2:APIでJSON形式404を返したい
class Api::UsersController < ApplicationController
rescue_from ActiveRecord::RecordNotFound do
render json: { error: "User not found" }, status: :not_found
end
def show
@user = User.find(params[:id])
render json: @user
end
end
パターン3:複数の find チェーン
def show
@user = current_user.posts.find(params[:id])
# ・current_user が nil → NoMethodError
# ・posts が空 → 問題なし
# ・id が存在しない → RecordNotFound
end
current_user.posts.find は「現在のユーザーの投稿の中から探す」ため、他人の投稿IDを指定すると404になる適切な動作です。
パターン4:スコープでの絞り込み後
def show
@article = Article.published.find(params[:id])
# 公開済み記事の中で探す
# 下書きや非公開の場合は RecordNotFound
end
セキュリティ的にも有用(公開記事のみ閲覧可能を強制)。
パターン5:複数条件で find_by!
def edit
@article = current_user.articles.find_by!(slug: params[:slug])
# slug で検索、なければ 404
end
パターン6:複数IDの一括検索
def show_multiple
@articles = Article.find([1, 2, 3])
# 3件全部見つからなければ RecordNotFound
end
許容したい場合:
@articles = Article.where(id: [1, 2, 3])
# 見つかった分だけ返す(空配列もOK)
rescue_from による404ハンドリング
カスタマイズの基本パターン。
全コントローラで共通の404処理
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
private
def record_not_found(exception)
render template: "errors/not_found", status: :not_found
end
end
ブロック形式
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound do |exception|
Rails.logger.warn "Not Found: #{exception.message}"
render template: "errors/not_found", status: :not_found
end
end
コントローラごとの個別処理
class ArticlesController < ApplicationController
rescue_from ActiveRecord::RecordNotFound do
redirect_to articles_path, alert: "記事が見つかりません"
end
def show
@article = Article.find(params[:id])
end
end
複数の例外をまとめて処理
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound,
ActionController::RoutingError,
ActionController::ParameterMissing,
with: :handle_404
rescue_from StandardError, with: :handle_500 unless Rails.env.development?
private
def handle_404
respond_to do |format|
format.html { render template: "errors/not_found", status: :not_found }
format.json { render json: { error: "Not Found" }, status: :not_found }
format.any { head :not_found }
end
end
def handle_500(exception)
Rails.logger.error "Internal Error: #{exception.message}"
Rails.logger.error exception.backtrace.join("\n")
respond_to do |format|
format.html { render template: "errors/internal_server_error", status: :internal_server_error }
format.json { render json: { error: "Internal Server Error" }, status: :internal_server_error }
end
end
end
rescue_from の順序
# 上から順にチェックされる
rescue_from StandardError, with: :handle_500 # ← 最後の砦
rescue_from ActiveRecord::RecordNotFound, with: :handle_404
より具体的な例外を先に書くのが原則。StandardError を先に書くと他の rescue_from が動きません。
ローカルコントローラ内での rescue
特定アクションだけ別の挙動にしたい場合:
class ArticlesController < ApplicationController
def show
@article = Article.find(params[:id])
rescue ActiveRecord::RecordNotFound
redirect_to articles_path, alert: "記事が見つかりません"
end
end
begin / rescue ブロック
def show
begin
@article = Article.find(params[:id])
rescue ActiveRecord::RecordNotFound => e
Rails.logger.warn "RecordNotFound: #{e.message}"
redirect_to articles_path
end
end
APIモードでのカスタマイズ
JSON API では HTML 404 ページではなく JSON レスポンスを返したい。
基本パターン
class Api::ApplicationController < ActionController::API
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
rescue_from ActiveRecord::RecordInvalid, with: :record_invalid
rescue_from ActionController::ParameterMissing, with: :parameter_missing
private
def record_not_found(exception)
render json: {
error: {
type: "RecordNotFound",
message: exception.message
}
}, status: :not_found
end
def record_invalid(exception)
render json: {
error: {
type: "RecordInvalid",
message: exception.message,
errors: exception.record.errors.full_messages
}
}, status: :unprocessable_entity
end
def parameter_missing(exception)
render json: {
error: {
type: "ParameterMissing",
message: exception.message,
parameter: exception.param
}
}, status: :bad_request
end
end
JSON:API 仕様準拠
def record_not_found(exception)
render json: {
errors: [
{
status: "404",
title: "Not Found",
detail: exception.message
}
]
}, status: :not_found
end
エラー詳細の制御
開発環境では詳細表示、本番では汎用メッセージ:
def record_not_found(exception)
message = if Rails.env.development?
exception.message
else
"リクエストされたリソースが見つかりません"
end
render json: { error: message }, status: :not_found
end
404ページのカスタマイズ
Rails 標準の404ページ
public/404.html
このファイルを編集すれば、デフォルトの404ページが変わります。
Erbテンプレートとして処理
# config/application.rb
config.exceptions_app = self.routes
# config/routes.rb
match '/404', to: 'errors#not_found', via: :all
match '/422', to: 'errors#unprocessable_entity', via: :all
match '/500', to: 'errors#internal_server_error', via: :all
# app/controllers/errors_controller.rb
class ErrorsController < ApplicationController
layout "error"
def not_found
render status: :not_found
end
def unprocessable_entity
render status: :unprocessable_entity
end
def internal_server_error
render status: :internal_server_error
end
end
<%# app/views/errors/not_found.html.erb %>
<div class="error-page">
<h1>404 - ページが見つかりません</h1>
<p>お探しのページは削除されたか、URLが間違っている可能性があります。</p>
<%= link_to "ホームに戻る", root_path, class: "btn" %>
<%= form_tag search_path, method: :get do %>
<%= text_field_tag :q, params[:q], placeholder: "検索" %>
<% end %>
</div>
動的ページにする利点
- ヘッダー・フッター共通化
- アナリティクス計測タグ埋め込み
- 検索ボックスや関連リンク表示
- 国際化(i18n)対応
関連メソッドの活用
find_or_initialize_by
「見つかれば返す、無ければ新規オブジェクト(DB保存はしない)」:
user = User.find_or_initialize_by(email: "alice@example.com")
if user.new_record?
user.name = "Alice"
user.save
end
find_or_create_by
「見つかれば返す、無ければ DB保存して返す」:
user = User.find_or_create_by(email: "alice@example.com") do |u|
u.name = "Alice"
end
⚠️ 競合状態の罠: 並行リクエストで同じレコード重複作成の可能性。find_or_create_by! で検証エラーを例外化、または unique index で DB レベル制約推奨。
find_each(バッチ処理)
大量レコード処理時:
User.find_each(batch_size: 100) do |user|
user.update_score
end
メモリ効率を保ちつつ全件処理。途中で RecordNotFound は出ない(あれば内部的に空配列扱い)。
DB index と RecordNotFound パフォーマンス
find(id) は主キー検索なので極めて高速。find_by(条件) は条件カラムにインデックスがないと遅くなります。
# 主キー検索(O(log n))
User.find(1)
# SELECT * FROM users WHERE id = 1 LIMIT 1
# 非インデックス列での検索(O(n))
User.find_by(email: "...") # email にindex無いと遅い
インデックス追加
class AddIndexToUsersEmail < ActiveRecord::Migration[8.0]
def change
add_index :users, :email, unique: true
end
end
unique: true で重複保存も防げます。
ログの読み方とデバッグ
スタックトレース
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=999):
app/controllers/users_controller.rb:8:in `show'
app/controllers/application_controller.rb:5:in `block in <main>'
ポイント:
- エラー直後:
Couldn't find User with 'id'=999から条件と何が無いか分かる - 最上位の自分のコード:
app/controllers/users_controller.rb:8が該当行
ログレベル設定
本番では大量に出ることがあるので、ログレベル調整:
# config/application.rb
config.action_dispatch.rescue_responses["ActiveRecord::RecordNotFound"] = :not_found
# 404 のログを WARN に抑える
config.log_level = :info
または rescue_from 内で:
rescue_from ActiveRecord::RecordNotFound do |exception|
Rails.logger.warn "404: #{exception.message} [#{request.method} #{request.fullpath}]"
render template: "errors/not_found", status: :not_found
end
Sentry / Rollbar 等での監視
通常、ボットや古いブックマークによる404はノイズ。エラートラッカーで除外設定:
# config/initializers/sentry.rb
Sentry.init do |config|
config.excluded_exceptions += [
'ActiveRecord::RecordNotFound',
'ActionController::RoutingError'
]
end
ベストプラクティス
1. find vs find_by の使い分け
| シーン | 推奨 |
|---|---|
| URLからのID(不在=404) | find |
| 任意条件検索(不在=正常) | find_by |
| 必須レコード(不在=異常) | find_by! |
2. ApplicationController に共通 rescue_from
すべてのコントローラに重複実装しない。
3. API は JSON 形式で返却
HTML 404 ページを返さない設計に。
4. セキュリティ的活用
# ❌ 他人の投稿も編集可能
@post = Post.find(params[:id])
# ✅ 自分の投稿のみ
@post = current_user.posts.find(params[:id])
# 他人の投稿IDなら 404(権限エラーではなく存在隠蔽)
5. リダイレクト先の検討
rescue_from ActiveRecord::RecordNotFound do
redirect_to root_path, alert: "ページが見つかりません"
# または
render "errors/not_found", status: :not_found
end
UXによって使い分け。
6. テストでカバー
RSpec.describe "GET /users/:id" do
it "存在しないIDで404" do
get "/users/999"
expect(response).to have_http_status(:not_found)
end
end
7. find_by の戻り値は必ずチェック
# ❌ 危険
user = User.find_by(email: email)
user.send_email # nil の可能性
# ✅ 安全
user = User.find_by(email: email)
return unless user
user.send_email
find_by 後の nil 確認はundefined method nil:NilClassの記事を参照。
トラブルシューティング
404になるべきが500になる
rescue_from StandardError が先に書かれている可能性:
# ❌ 順序が悪い
rescue_from StandardError, with: :handle_500 # ← これが先に発火
rescue_from ActiveRecord::RecordNotFound, with: :handle_404
# ✅ 具体的な例外を先に
rescue_from ActiveRecord::RecordNotFound, with: :handle_404
rescue_from StandardError, with: :handle_500
本番でカスタム404ページが出ない
# config/environments/production.rb で
config.consider_all_requests_local = false # ← false にする
config.exceptions_app = self.routes # ← 動的404の場合
開発環境で404画面を見たい
# config/environments/development.rb
config.consider_all_requests_local = false
または、URLに ?debug=false を付けて試す。
ActiveRecord::RecordNotFound: Couldn’t find all
ActiveRecord::RecordNotFound: Couldn't find all Articles with 'id': (1, 2, 3) (found 2 results, but was looking for 3)
User.find([1, 2, 3]) で1件でも見つからない時に発生。
対処:
Article.where(id: [1, 2, 3])
# 見つかった分だけ返す
ActiveRecord::SoleRecordExceeded
User.where(email: "common@example.com").sole
# 2件以上ヒット → SoleRecordExceeded
sole は厳密に1件期待する場合のみ使用。
ボットからの404大量発生
GET /wp-admin
GET /.env
GET /admin/login
セキュリティスキャンによる404の嵐。対処:
- ログレベルを下げる
- Rate Limiting(rack-attack 等)
- WAF / CDN レベルでブロック
関連エラーとの違い
NilClass NoMethodError
@user.name
# @user が nil なら NoMethodError
find_by の戻り値(nil)に対してメソッドを呼ぶと出ます。詳細はundefined method nil:NilClass の記事。
ActionController::RoutingError
ActionController::RoutingError (No route matches [GET] "/nonexistent")
URLにマッチするルートがない場合。これも404ですが、RecordNotFoundとは別物。
ActiveRecord::RecordInvalid
User.create!(email: "invalid")
# => ActiveRecord::RecordInvalid (Validation failed: ...)
バリデーション失敗時。
ActiveRecord::StatementInvalid
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column does not exist
SQL自体が無効。マイグレーション漏れ等。
ActionController::ParameterMissing
params.require(:user).permit(:name)
# params[:user] が無い場合
違いの一覧
| 例外 | 発生原因 | HTTPステータス(自動) |
|---|---|---|
| ActiveRecord::RecordNotFound | find/find_by!でレコード不在 | 404 |
| ActionController::RoutingError | ルート未定義 | 404 |
| ActiveRecord::RecordInvalid | バリデーション失敗 | 422 |
| ActiveRecord::StatementInvalid | SQL実行失敗 | 500 |
| ActionController::ParameterMissing | パラメータ不足 | 400 |
よくある質問(FAQ)
Q1. find と find_by はどちらを使うべきですか?
| シーン | 推奨 |
|---|---|
| URLパラメータからの取得 | find(不在=404) |
| 任意条件・不在も正常 | find_by(nil返却) |
| 必須レコード | find_by!(不在=例外) |
Q2. 404 にカスタム HTML を返したい
# config/routes.rb
match '/404', to: 'errors#not_found', via: :all
# config/application.rb
config.exceptions_app = self.routes
app/controllers/errors_controller.rb で not_found アクション定義。
Q3. API でカスタム JSON を返したい
class Api::ApplicationController < ActionController::API
rescue_from ActiveRecord::RecordNotFound do |e|
render json: { error: e.message }, status: :not_found
end
end
Q4. テストで RecordNotFound を確認する方法
# RSpec
it "存在しないIDで404" do
get "/users/999"
expect(response).to have_http_status(:not_found)
end
# Minitest
test "404 for non-existent user" do
get "/users/999"
assert_response :not_found
end
Q5. RecordNotFound を意図的に発生させる方法
raise ActiveRecord::RecordNotFound, "Custom message"
特定条件でメソッドの途中から 404 を返したい場合に使えます。
Q6. 404 のログを抑制したい
rescue_from ActiveRecord::RecordNotFound do |e|
Rails.logger.warn(e.message) # WARN レベルで記録
render "errors/not_found", status: :not_found
end
Sentry等のエラートラッカーでも除外推奨。
Q7. find のN+1問題はありますか?
# ❌ N+1
@articles = Article.find([1, 2, 3])
@articles.each { |a| a.author.name } # author の SELECT が3回
# ✅ includes で解決
@articles = Article.includes(:author).find([1, 2, 3])
Q8. routes でidが文字列だと?
get '/articles/:id', to: 'articles#show'
Article.find("abc")
# => ActiveRecord::RecordNotFound (Couldn't find Article with 'id'=abc)
数字以外も find に渡されますが、PostgreSQL等では型変換エラーになる場合も。
Q9. 404 でリダイレクトすべき?
UXによります:
- エラーページ表示: 「404 – 見つかりません」(検索ヒント付き)
- トップにリダイレクト:
redirect_to root_path, alert: "..." - API: JSON エラーレスポンス
ユーザーの混乱を最小化する方法を選択。
Q10. find の前にバリデーションすべき?
整数チェック等は事前にした方が良い:
def show
unless params[:id].to_s.match?(/\A\d+\z/)
return render status: :bad_request
end
@user = User.find(params[:id])
end
ただし、Rails は通常型変換を自動でしてくれます。
Q11. SoftDelete を使っている場合
paranoia や discard gem で論理削除している場合:
# 論理削除されたレコードは find しても見つからない
User.find(deleted_user_id)
# => RecordNotFound
# 削除済みも含めて検索
User.with_deleted.find(deleted_user_id)
Q12. UUID をPKに使う場合
class User < ApplicationRecord
# id がUUIDの場合
end
User.find("invalid-uuid")
# => ActiveRecord::StatementInvalid(型変換エラー)
# RecordNotFound にしたい場合は事前バリデーション
def show
unless params[:id].match?(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/)
raise ActiveRecord::RecordNotFound
end
@user = User.find(params[:id])
end
参考リンク・関連資料
Rails 公式
- ActiveRecord::FinderMethods(API doc) – find系メソッド
- ActionController::Rescue(API doc) – rescue_from
- Active Record Query Interface(Guide) – クエリ
- Configuring Action Dispatch(Guide) – exceptions_app
関連 Gem
- paranoia – 論理削除
- discard – 論理削除(モダン)
- rack-attack – Rate Limiting
関連記事(本サイト)
- undefined method nil:NilClass エラー対処 – find_by の nil 問題
- Rails 8 アップグレードガイド – Rails 8 全般
- Solid Queue 使い方 – Rails 8 Solid Trifecta
- Solid Cache 使い方 – 同上
- Solid Cable 使い方 – 同上
- Propshaft 使い方 – Rails 8 アセットパイプライン
- MySQL 1146 Table doesn’t exist – DB エラー(テーブル不在)
- MySQL 1045 access denied – DB接続エラー
まとめ
ActiveRecord::RecordNotFound は Rails で頻出ですが、Rails の標準的な404処理として活用することで、シンプルかつ堅牢なコードを書けます。要点を再整理します。
- 本質: find系メソッドの「レコード未発見」例外、本番では自動的に404
- find系の使い分け: find(404)、find_by(nil)、find_by!(例外)、first/take系
- rescue_from: ApplicationController で共通404処理
- API では: JSON フォーマットでステータス404を返す
- 404ページのカスタマイズ: routes + ErrorsController で動的化
- セキュリティ的活用:
current_user.posts.findで権限エラーを存在隠蔽 - 関連メソッド: find_or_initialize_by、find_or_create_by、find_each
- ベストプラクティス: 具体的例外を先に rescue、テストでカバー、ログ抑制
これらの知識は、Rails の Web アプリ・API 開発・本番運用すべてで活用できます。本記事をブックマークしておけば、404 ハンドリングと例外設計を適切に実装できるようになります。
本記事は2026年6月時点の情報をもとに、Ruby on Rails 7.x / 8.x での動作確認・公式ドキュメントに基づき作成しています。Rails のバージョンによって挙動が異なる場合があるため、最新の情報はRails公式ガイドもあわせてご確認ください。
-
前の記事
「apt-get update」で404 Not Foundになる原因と解決方法|Ubuntu/Debian完全解説 2026.06.29
-
次の記事
【完全リファレンス】Linuxでシンボリックリンクを作成・確認・削除する方法|ln・readlink・unlink完全ガイド 2026.06.30
コメントを書く