Parameters#select と #reject がブロック未指定時に Enumerator を返すように修正

rails/rails

Rails 8.1系の ActionController::Parameters では、selectreject がブロックなしで呼び出された際に例外が発生していたが、Ruby の Hash#select/#reject と同様に Enumerator を返すよう修正された。

背景

ActionController::Parameters#select#reject は内部のハッシュ (@parameters) をラップしているが、ブロックが与えられない場合に to_enum ガードが欠如していた。その結果、@params.select が裸の Enumerator を返し、続く new_instance_with_inherited_permitted_status へ渡すと NoMethodError: undefined method 'each_key' for an instance of Enumerator がスローされた。

同様のガードは他の Enumerable ラッパー(each_pairtransform_values など)で既に実装されており、一貫性が欠如していた点が問題である。

この不整合を解消し、ブロックなしでも安全に列挙子を取得できるようにすることが本修正の目的である。

技術的な変更

selectrejectblock_given? チェックと to_enum ガードを追加し、ブロックが無い場合は即座に列挙子を返すようにした。既存のロジックはブロックが提供されたときだけ実行され、挙動に後方互換性は保たれる。

@@
-    def select(&block)
-      new_instance_with_inherited_permitted_status(@parameters.select(&block))
-    end
+    def select(&block)
+      return to_enum(:select) unless block_given?
+      new_instance_with_inherited_permitted_status(@parameters.select(&block))
+    end
@@
-    def reject(&block)
-      new_instance_with_inherited_permitted_status(@parameters.reject(&block))
-    end
+    def reject(&block)
+      return to_enum(:reject) unless block_given?
+      new_instance_with_inherited_permitted_status(@parameters.reject(&block))
+    end

テストスイートにもブロックなしで Enumerator が返ることを確認するケースが追加された。これにより、selectreject の両方で Enumerator が返り、続く each によって再び ActionController::Parameters インスタンスが生成されることが保証される。

@@
   test "reject without a block returns an enumerator" do
     assert_kind_of Enumerator, @params.reject
     assert_kind_of ActionController::Parameters, @params.reject.each { |k, v| false }
   end
@@
   test "select without a block returns an enumerator" do
     assert_kind_of Enumerator, @params.select
     assert_kind_of ActionController::Parameters, @params.select.each { |k, v| true }
   end

設計判断

本修正は 既存の Enumerable ラッパーと同様の to_enum ガードを導入 するという最小限の変更に留めた。新たな設定キーや API の追加は行わず、メソッド本体に guard 文を挿入するだけで済むため、後方互換性が確保された。

また、Ruby 標準の Hash と同等の挙動を提供することで、開発者は select.with_index { … } のようなチェーン操作を期待通りに利用でき、API の一貫性が向上した。

まとめ

Parameters#selectParameters#reject がブロック未指定時に Enumerator を返すようになり、例外が除去されて API の整合性が改善された。実装は guard 文の追加だけで済み、既存コードへの影響はなく、テストによって安全性が検証されている。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

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

カスタムMarkdown構文 ✓ PASS

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

コードブロックは `ruby:ファイルパス` 形式で正しく記述されており、PRリンクは `[ #57721 ](URL)` の形で正しくハイパーリンク化されています。

対象読者への適合性 ✓ PASS

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

専門的なRails内部実装に関する記述で、エンジニア向けの内容になっており、過度な初心者向け解説はありません。

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

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

各セクションは総論パラグラフ→各論パラグラフ→結論パラグラフで構成され、段落はトピックセンテンスで始まり1段落1トピック、長さも適切です。空行で区切られています。

Diff内容との照合 ✓ PASS

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

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

技術用語の正確性 ✓ PASS

技術用語の正確な使用

使用されている技術用語(Enumerator、to_enum、guard、block_given? など)はPRで用いられている表現と一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

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

技術的説明はPRの目的・実装内容と整合しており、因果関係も論理的です。

事実の突合 ✓ PASS

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

記事の主張は全てPR情報で裏付けられており、根拠のない推測や外部知識の付加はありません。

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

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

PR番号 #57721 などの数値・固有名詞は正確です。

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

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

記事タイトルはPRタイトルの意味を日本語で的確に表現しており、一致しています。

外部知識の正確性 ✓ PASS

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

バージョンサポート状況やリリース日程といった外部情報は記載されておらず、問題はありません。

時間表現の正確性 ✓ PASS

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

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