`Array#to_query` が空ハッシュを含む場合の二重 `&&` を修正

rails/rails

配列に空ハッシュが含まれると Array#to_query&& を二重出力していたバグを、filter_map による空文字列の除去で修正しました。これにより、WHATWG URL 標準に準拠した正しいクエリ文字列が生成されます。

背景

Array#to_query は、配列要素をそれぞれ to_query に変換して & で結合していましたが、空ハッシュを含む場合に不正なクエリ文字列を生成していました。

具体的には、{a: [1, {}, 2]}.to_query を呼び出すと、空ハッシュ {}to_query が空文字列 "" を返すため、& の間に何もない "a%5B%5D=1&&a%5B%5D=2" が出力されていました。WHATWG URL 標準application/x-www-form-urlencoded パーサーは & で分割する際、2つの & の間の空文字列を空の name/value ペアとして解釈するため、これはパース上の誤動作を引き起こします。

なお、Hash#to_query はトップレベルで空ハッシュをすでにスキップする実装になっており、今回の修正はその挙動と一貫性を持たせるものです。

技術的な変更

activesupport/lib/active_support/core_ext/object/to_query.rbArray#to_query 実装が、collect から filter_map を使った実装に変更されました。

変更前:

collect { |value| value.to_query(prefix) }.join "&"

変更後:

filter_map { |value|
  q = value.to_query(prefix)
  q unless q.empty?
}.join "&"

各要素の to_query 結果を変数 q に受け取り、空文字列であれば nil を返すことで filter_map が自動的に除外します。結合前のリストから空要素が取り除かれるため、& が連続することがなくなります。

テストは activesupport/test/core_ext/object/to_query_test.rb に追加され、{a: [1, {}, 2]}.to_query"a%5B%5D=1&a%5B%5D=2" を返すことを検証しています。

設計判断

filter_map による除外 という最小限の変更で修正が実現されています。

空ハッシュのケースだけを特別扱いするのではなく、to_query が空文字列を返すあらゆるケースを汎用的に除外しています。nil.to_query"" を返すため、配列に nil が含まれる場合も同様に除外される動作となります。既存の Array#to_query が空配列の場合に早期リターンするコードパスはそのままに、通常パスのみ変更されており、変更の局所性が保たれています。

まとめ

本修正は、Hash#to_query が持つ「空を読み飛ばす」という既存の挙動を Array#to_query にも一貫して適用した変更です。collect から filter_map への差し替えだけで、WHATWG URL 標準への準拠を確保しつつ、APIインターフェースへの影響を最小化しています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
549246a8

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

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

リード文(総論)、背景・技術詳細・設計判断(各論)、まとめ(結論)という「総論→各論→結論」の3部構成が明確に適用されており、非常に分かりやすいです。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライト(```ruby:ファイルパス)およびPR番号のリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

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

専門用語(`to_query`, `filter_map`, WHATWG URL 標準など)が適切に使用されており、専門知識を持つエンジニアという対象読者に適合した内容です。

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

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

各セクションが要約から詳細へと展開され、各段落がトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られており、可読性が高いです。

Diff内容との照合 ⚠ WARNING

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

引用されているコードはDiffの内容と技術的に等価ですが、変更後のコードブロックが複数行から1行にまとめられており、フォーマットが完全に一致していません。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

PR内で使用されている `Array#to_query`, `WHATWG URL Standard` などの技術用語を正確に反映しており、誤用は見られません。

説明の技術的正確性 ✓ PASS

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

「`filter_map`で空文字列を除去することで二重の`&`を防ぐ」という説明は、Diffのコード変更と論理的に整合しており、技術的に正確です。

事実の突合 ⚠ WARNING

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

「設計判断」セクションで言及されている「配列に `nil` が含まれる場合も同様に除外される」という挙動は、PR情報には明記されていません。コードから導かれる技術的に妥当な補足ですが、厳密にはPR情報外の事実です。

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

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

PR番号(#57500)やファイルパスが正確に記載されています。

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

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

記事タイトルは、PRのタイトル「Fix Array#to_query producing double && when array contains empty hash」の内容を正確に要約しています。

外部知識の正確性 ✓ PASS

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

WHATWG URL標準への言及はPR Descriptionに基づいています。バージョンサポート情報など、PRに記載のない外部知識の捏造はありません。

時間表現の正確性 ✓ PASS

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

PR内の「already」という表現を「すでに」と正しく訳出しており、時間表現の歪曲はありません。