Array#to_query が空要素を除外するよう修正
Array#to_query が空の配列要素をクエリ文字列に残す問題を修正し、空ハッシュ要素と同様にスキップするようになりました。これにより、ネストしたパラメータ生成時の不整合が解消されます。
背景
Array#to_query が空配列要素を除外しないという不整合がありました。[].to_query(prefix) は nil.to_query(prefix) に委譲し空文字列になるのに対し、空配列要素は nil にならず、キーだけがエスケープされた a%5B%5D%5B%5D が残ります。その結果、{ a: [1, [], 2] }.to_query が期待される "a%5B%5D=1&a%5B%5D=2" ではなく、余分なセグメントを含む文字列を生成していました。
技術的な変更
Array#to_query の実装に空コレクションのガードを追加しました。変更前は各要素を value.to_query(prefix) に変換し、空文字列でなければ結合していましたが、以下のように空ハッシュまたは空配列を事前にスキップするロジックを挿入しました。
@@ -60,8 +60,8 @@ def to_query(key)
nil.to_query(prefix)
else
- q = value.to_query(prefix)
- q unless q.empty?
+ next if (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
+ value.to_query(prefix)
}.join "&"
end
end
この変更により、空のハッシュ要素と同様に空配列要素もクエリ文字列に含まれなくなります。トップレベルで [].to_query("a") が "a%5B%5D" を返す既存の振る舞いは、別の if empty? ブランチで処理されるため影響を受けません。
テストケースを追加して回帰防止を確実にしました。新たに test_array_with_empty_array が activesupport/test/core_ext/object/to_query_test.rb に追加され、空配列要素を含む配列が正しく "a%5B%5D=1&a%5B%5D=2" にシリアライズされることを検証します。
@@
def test_array_with_empty_hash
assert_query_equal "a%5B%5D=1&a%5B%5D=2", a: [1, {}, 2]
end
+
+ def test_array_with_empty_array
+ assert_query_equal "a%5B%5D=1&a%5B%5D=2", a: [1, [], 2]
+ end
テストは修正前に失敗し、修正後に通過することが CI で確認されています。
設計判断
既存の空コレクション判定ロジックを再利用する形で最小限の変更に留めました。Hash#to_query ですでに採用されている next if (value.is_a?(Hash) || value.is_a?(Array)) && value.empty? をそのまま Array#to_query に持ち込み、コード重複を避けつつ挙動の一貫性を確保しています。加えて、トップレベルの空配列は別ブランチで処理されるため互換性が保持され、既存アプリケーションへの影響はありません。
まとめ
この PR は、Array#to_query が空配列要素をクエリ文字列に残す不具合を修正し、Hash#to_query と同様のスキップロジックを導入しました。3 行程度のシンプルな差分で挙動の一貫性を実現し、追加テストにより将来的なリグレッションを防止します。