Composite Primary Key の単一レコード更新をサポート

rails/rails

ActiveRecord のクラスメソッド updateupdate! が、単一レコードの複合主キー更新で誤って RecordNotFound を発生させる問題を修正し、シングルキーと同様に扱えるようになりました。

背景

これまで update / update! は引数 id が配列かどうかで「単一」か「複数」かを判定していました。
複合主キー を持つモデルでは、単一レコードの id 自体が配列(例: ["author_id","id"])になるため、配列判定に引っ掛かり複数 ID と誤認識され、内部で find が個々の要素に対して実行され ActiveRecord::RecordNotFound が送出されました。
この挙動はシングルプライマリキーと非対称であり、Model.update(record.id, attrs) が期待通りに動作しないという実装上の不整合を生んでいました。

技術的な変更

activerecord/lib/active_record/persistence.rbupdate_multiple_ids? ヘルパーメソッドが新設され、複合主キーかどうかを踏まえて ID の形状を正しく判定します。

def update_multiple_ids?(id)
  if composite_primary_key?
    id.is_a?(Array) && id.first.is_a?(Array)
  else
    id.is_a?(Array)
  end
end

updateupdate! の先頭条件が if id.is_a?(Array) から if update_multiple_ids?(id) に置き換えられ、単一レコードの配列 ID が複数判定に混入しなくなります。
また、:all(デフォルト)パスのチェックが最初に行われるよう順序が調整され、既存の引数省略動作は維持されています。
テスト activerecord/test/cases/persistence_test.rb では、単一および複数の複合キー対象レコードに対する update / update! の正しい動作を検証するケースが追加され、リグレッション防止が確保されています。

設計判断

判定ロジックの共通化Relation#destroy の判定方式の踏襲 が採用されました。
Relation#destroy では「配列の配列」かどうかで複数削除を判定しており、同様の判断基準を update 系に持ち込むことでコードの一貫性と保守性が向上します。
新たなメソッドはプライベートとし、外部 API には影響を与えないため、既存利用者への破壊的変更は発生しません。

まとめ

この PR は、複合主キーを持つモデルでも Model.update(id, attrs) が単一レコード更新を正しく処理できるようにし、シングルキーと同等の使い勝手を提供します。判定ロジックの共通化により内部実装がシンプルになり、将来的な類似機能拡張にも対応しやすくなります。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
7d88182b

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

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

リード文→背景→技術的な変更→設計判断→まとめの5部構成が明確で、各要素が揃っている。まとめはリード文の単なる繰り返しではなく意義を付加している。

カスタムMarkdown構文 ⚠ WARNING

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

コードブロックのファイル名付きハイライトは正しい形式 (```ruby:activerecord/lib/active_record/persistence.rb) 。GitHubリンクは [PR #57655](URL) となっているが、仕様が求める [#57655](URL) の形式と若干異なる。

対象読者への適合性 ✓ PASS

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

Rails の内部実装に関する説明で、対象はエンジニアであることが前提となっており、過度な基礎解説はない。

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

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

各セクションは総論・各論・結論の流れになっており、段落はトピックセンテンスで始まり、1段落1トピック、6文以内で空行で区切られている。

Diff内容との照合 ✓ PASS

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

記事中のコードブロックは Diff に示された追加コードと完全に一致し、`update_multiple_ids?` の実装内容と置換箇所の説明も正確。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

用語は PR と一致し、誤用や不適切な表現は見られない。

説明の技術的正確性 ✓ PASS

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

技術的説明は PR の概要・原因・修正内容と合致し、因果関係も論理的に記述されている。

事実の突合 ✓ PASS

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

記事の主張はすべて PR の記載内容に基づいており、根拠のない推測や外部知識の付加はない。

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

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

PR 番号 #57655 等の数値は正しい。その他数値やバージョン情報は記載されていない。

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

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

タイトルは PR の要旨「Support a single composite primary key id in `update`/`update!`」を日本語で適切に表現している。

外部知識の正確性 ✓ PASS

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

記事内に PR 以外の外部知識(LTS、EOL 等)は含まれていない。

時間表現の正確性 ✓ PASS

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

時間表現は使用されておらず、矛盾もない。