`ActionController::Parameters`に`deep_transform_values`を追加

rails/rails

ActionController::Parametersdeep_transform_valuesdeep_transform_values!が追加され、Strong Parametersの枠組みを維持したまま全ネスト値の一括変換が可能になりました。これにより、ホワイトスペース除去や文字列正規化のためだけにto_unsafe_hを呼び出す必要がなくなります。

背景

これまで、ネストされたパラメータの全値を変換するにはto_unsafe_hを通じてプレーンなHashに変換するしかありませんでした。この方法ではpermitted/unpermittedの区別が失われ、Strong Parametersのガードレールを意図せず迂回してしまいます。

具体的には、バリデーション前にすべての文字列からホワイトスペースを除去する処理が典型例です。これは日常的な正規化タスクであるにもかかわらず、既存の手段では以下のように書くしかありませんでした:

params.to_unsafe_h.deep_transform_values { |v| v.is_a?(String) ? v.strip : v }

ActionController::Parametersは既にdeep_transform_keysdeep_transform_keys!を持ち、Active SupportもHashdeep_transform_valuesを提供していました。今回の追加はこの非対称性を解消し、キー変換とバリュー変換の一貫したインターフェースを実現します。

技術的な変更

strong_parameters.rbdeep_transform_valuesdeep_transform_values!の2メソッドが追加され、内部処理を担うプライベートメソッド_deep_transform_values_in_object_deep_transform_values_in_object!が実装されました。

非破壊版のdeep_transform_valuesは、new_instance_with_inherited_permitted_statusを通じて変換結果を新しいParametersインスタンスに包み直します。これは既存のdeep_transform_keysと同じパターンです:

def deep_transform_values(&block)
  new_instance_with_inherited_permitted_status(
    _deep_transform_values_in_object(@parameters, &block)
  )
end

def deep_transform_values!(&block)
  @parameters = _deep_transform_values_in_object!(@parameters, &block)
  self
end

ブロックはリーフ値(末端の値)にのみ渡され、HashArrayParametersのような中間ノードはトラバーサルの対象となるだけでブロックには渡されません。また、ファイル先頭ではactive_support/core_ext/hash/deep_transform_valuesのrequireが追加され、Active Supportの実装との連携が明示されています。

メソッドの動作を示すと、以下のようになります:

params = ActionController::Parameters.new(
  user: {
    email: "  ALICE@EXAMPLE.COM  ",
    profile: { bio: "  Hello world  " }
  }
)

params.deep_transform_values { |v| v.is_a?(String) ? v.strip.downcase : v }
# => #<ActionController::Parameters {"user"=>#<ActionController::Parameters {"email"=>"alice@example.com", "profile"=>#<ActionController::Parameters {"bio"=>"hello world"} permitted: false>} permitted: false>} permitted: false>

# permit!後のインスタンスでもpermitted?が引き継がれる
params.permit!
params.deep_transform_values { |v| v }.permitted? # => true

テストはaccessors_test.rbmutators_test.rbに分けて追加されており、permitted状態の継承・リーフ値のみへの適用・非破壊性(deep_transform_valuesが元のインスタンスを変更しないこと)がそれぞれ検証されています。

設計判断

permitted?ステータスの継承が明示的に設計されています。変換後のインスタンスもpermit / expectを通過させないとマスアサインメントには使えないという制約が保たれており、Strong Parametersの安全モデルが損なわれません。

既存のdeep_transform_keysの実装パターンをそのまま踏襲しています。new_instance_with_inherited_permitted_statusの再利用、case文によるオブジェクト種別の分岐、!版がselfを返す設計など、コードベースの一貫性が優先されています。新たな設計上の概念は導入されておらず、既存のパターンへの準拠が選ばれています。

まとめ

本PRは、deep_transform_keysとの対称性を埋めることで、Strong Parametersを正しく使いながら値の正規化処理を記述できる手段を追加しました。to_unsafe_hという安全でない迂回路を排除し、日常的な前処理をStrong Parametersの保護下で完結させられるようになったことが、この変更の本質的な意義です。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
700af2f8

この記事は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リンク記法の正確性

ファイル名付きシンタックスハイライトとGitHubのPRリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

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

専門用語が適切に使用されており、Railsエンジニアという対象読者に適した技術レベルで書かれています。

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

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

各セクションが「総論→各論」で構成され、各パラグラフはトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られており、可読性が高いです。

Diff内容との照合 ✓ PASS

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

記事内で引用されているコードブロック、ファイル名、テストに関する記述は、提供されたDiff情報と正確に一致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「Strong Parameters」「permitted?」「マスアサインメント」などの技術用語が、文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

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

「to_unsafe_hの問題点」「permitted?ステータスの継承」「リーフ値のみへの適用」といった技術的な説明は、PR情報とDiffコードによって裏付けられており、正確です。

事実の突合 ✓ PASS

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

記事内のすべての主張は、PRのDescriptionやDiff内のコードで裏付けられており、ハルシネーション(創作)は見られません。「設計判断」もコードから読み取れる事実に基づいています。

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

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

PR番号(#57340)やメソッド名、ファイル名などの固有名詞はすべて正確です。

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

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

記事のタイトルはPRのタイトルと一致しており、内容もPRの主題を正確に反映しています。

外部知識の正確性 ✓ PASS

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

PR情報に記載のないバージョンサポート状況やリリース日程などの外部知識は含まれておらず、提供された情報源に忠実です。

時間表現の正確性 ✓ PASS

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

「これまで」「既に」といった時間表現が、PR Descriptionの内容と一致しており、正確な時系列で記述されています。