`ActionController::Parameters#fetch_values` による複数キーの一括取得
ActionController::Parameters に fetch_values メソッドが追加され、複数のパラメータを一度に取得できるようになりました。Ruby の Hash#fetch_values と同様のインターフェースで、存在しないキーに対するエラーハンドリングも一貫して行えます。
背景
これまで複数の必須パラメータを取得するには、fetch を複数回呼び出す必要があり、コードが冗長になっていました。たとえば name と age と email の3つを取得する場合、次のように3行の fetch 呼び出しが必要でした。
name = params.fetch(:name)
age = params.fetch(:age)
email = params.fetch(:email)
Ruby の Hash には複数キーを一括取得する fetch_values が存在しますが、ActionController::Parameters にはこれに相当するメソッドがなく、同等の操作を簡潔に書く手段がありませんでした。今回の追加はこのギャップを埋めるものです。
技術的な変更
actionpack/lib/action_controller/metal/strong_parameters.rb に fetch_values メソッドが実装されました。内部的には @parameters(通常の Hash)の fetch_values に処理を委譲しつつ、不足キーのハンドリングと値の変換を ActionController::Parameters に合わせて上書きしています。
def fetch_values(*keys)
original_key_lookup = keys.index_by { |key| key.to_s }
values = @parameters.fetch_values(*keys) do |missing_key|
original_key = original_key_lookup[missing_key]
if block_given?
yield original_key
else
raise ActionController::ParameterMissing.new(original_key, @parameters.keys)
end
end
values.map! { |value| convert_value_to_parameters(value) }
end
実装で注目すべきポイントが original_key_lookup の構築です。@parameters は内部的にすべてのキーを文字列に変換して保持しているため、Hash#fetch_values がミスヒット時のブロックに渡してくるのは文字列化されたキーになります。keys.index_by { |key| key.to_s } で文字列キーから元のキー(シンボルまたは文字列)への逆引きテーブルを作成しておくことで、ParameterMissing エラーや yield に渡すキーとして元の型を保持できます。最後の values.map! は既存の fetch と同様に、ネストしたパラメータを ActionController::Parameters に変換する処理です。
params = ActionController::Parameters.new(name: "Francesco", age: 22)
# 複数キーを一括取得
params.fetch_values(:name, :age)
# => ["Francesco", 22]
# キーが不足している場合は ParameterMissing を発生させる
params.fetch_values(:name, :none)
# => ActionController::ParameterMissing: param is missing or the value is empty or invalid: none
# ブロックを渡すとデフォルト値を返す
params.fetch_values(:name, :none) { |key| key }
# => ["Francesco", :none]
パーミッション状態も正しく引き継がれます。permit! 済みのパラメータから取得した場合は permitted、未許可の場合は unpermitted のまま返されます。
設計判断
Hash#fetch_values への委譲 という実装方針は、内部ストアをそのまま活用できるシンプルな設計です。ただし、ActionController::Parameters 独自の仕様(シンボル・文字列キーの同一視、ParameterMissing 例外、パーミッション状態の伝播)をすべて満たすため、ブロック引数内でのキー型復元と map! による後処理という2段階の調整が加えられています。
ブロックなしの場合に KeyError ではなく ActionController::ParameterMissing を raise する点は既存の fetch と一貫しており、コントローラ層でのエラーハンドリング(rescue_from ActionController::ParameterMissing など)がそのまま機能します。新たなエラー型を導入せず既存の例外体系に乗ることで、利用者側の変更を最小化する判断といえます。
まとめ
fetch_values の追加は、ActionController::Parameters と Ruby の Hash との API ギャップを埋める実用的な拡張です。内部実装は Hash#fetch_values への委譲を基盤としつつ、Strong Parameters の型・パーミッション・例外仕様を忠実に踏襲しており、既存コードに影響を与えることなく複数キー取得のコードを簡潔に記述できます。