Composite Primary Keyで find(nil) が RecordNotFound を返すように修正

rails/rails

Composite primary key を持つモデルで Model.find(nil)ActiveRecord::RecordNotFound を返すように実装を調整しました。これにより、ドキュメント通りの例外が一貫して発生します。

背景

Composite primary key を持つモデルで find(nil) を実行すると NoMethodError: undefined method 'first' for nil が発生していました。Key::Composite#expects_multiple_ids?value.first.is_a?(Array) だけを評価し、nil に対して first を呼び出すガードが欠如していたことが原因です。結果として、ActiveRecord が期待する ActiveRecord::RecordNotFound ではなく、内部エラーが外部へ漏れていました。

この挙動はシングルキーのパスとは対照的です。シングルキーの場合は Key::Single#expects_multiple_ids?value.is_a?(Array) と nil‑safe にチェックするため、nil が渡っても正しく RecordNotFound がスローされます。テストスイートでもシングルキーは既にこの動作を検証しており、差異が問題視されていました。

技術的な変更

Key::Composite#expects_multiple_ids?nil 安全ガード を追加し、配列判定を二段階で行うようにしました。

@@
-        value.first.is_a?(Array)
+        value.is_a?(Array) && value.first.is_a?(Array)

この変更により、valuenil の場合は false を返すため、検索ロジックは RecordNotFound へフォールバックします。既存の nil 以外の入力に対しては従来と同等の挙動を維持し、機能的な影響はありません。

テストも追加して、Composite キーのモデルで findfind(nil) が期待通り ActiveRecord::RecordNotFound をスローすることを明示しました。

@@
   def test_find_with_ids_with_no_id_passed
     assert_equal "id", exception.primary_key
   end
+
+  def test_find_with_no_id_passed_on_composite_primary_key_model
+    assert_raises(ActiveRecord::RecordNotFound) { Cpk::Book.find }
+    assert_raises(ActiveRecord::RecordNotFound) { Cpk::Book.find(nil) }
+  end

設計判断

この修正は インターフェースの変更を伴わないガード条件の追加 だけで問題を解決しています。既存の Key::Composite の API はそのまま残り、外部からの呼び出し方に影響はありません。

また、Key::Single と同様の nil‑safe 判定 を採用したことで、コードベース全体の一貫性が向上しました。二重の配列チェックは意図的に value.is_a?(Array) を先に評価し、不要なメソッド呼び出しを防ぐシンプルなトレードオフです。

まとめ

Key::Composite#expects_multiple_ids? に nil 安全ガードを加えることで、Composite primary key モデルでの find(nil) が正しい例外 ActiveRecord::RecordNotFound を返すようになりました。変更は最小限で後方互換性を維持しつつ、ドキュメント記載通りの挙動を実現しています。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
948e9f86

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文があり、背景・技術的変更・設計判断・まとめの各セクションが揃っており、総論→各論→結論の構成が明確です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライトが正しい形式で使用され、PRリンクも適切に記述されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Railsエンジニア向けの技術的詳細が中心で、余計な初心者向け説明はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論・各論・結論の段落構成で、トピックセンテンスが先頭にあり、1段落1トピック、長さも適切です。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内のコードブロックは提供されたDiffと完全に一致しており、変更点が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

用語はPRで使用されているものと一致し、誤用は見られません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的説明はPRの問題点と修正内容に沿っており、根拠が明確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

すべての主張がPRタイトル・説明・Diffで裏付けられており、捏造や推測はありません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#57719)やコード行の変更内容など、数値・固有名詞は正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルはPRタイトルの内容を正確に要約しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PRに記載されていない外部知識は含まれていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の歪曲はなく、PRの記述と一致しています。