Rails 7: ActionController::Parameters.to_hにブロックを渡せるようになった(翻訳)
RailsのActionController::Parameters
は、リクエストのデータをコントローラのアクションに渡すときに便利な方法です。コントローラのアクションにパラメータ付きのリクエストを行うときは常に最大限の注意が必要ですが、そのときに有用なのがActionController::Parameters
です。
Rails 7から、ActionController::Parameters
オブジェクトをto_h
メソッドで標準のHashに変換できるようになりました。これは、データをコントローラに渡す方法をカスタマイズしたい開発者にとって朗報です。また、これによってクライアントコードを一切変更せずにパラメータの振る舞いを変更できるようになります。
Productモデルをscaffoldで作成し、product_name
、product_price
、product_image
という属性を持たせたとしましょう。
class ProductsController < ApplicationController
def create
@product = Product.new(product_params)
respond_to do |format|
# HTMLとJSONでレスポンスを返す
end
end
private
# 信頼できるパラメータリストのみ受け取りを許可する
def product_params
params.require(:product).permit(:product_name, :product_price, :product_image)
end
end
これで、フロントエンドアプリが適切なリクエストを適切なパラメータ付きで送信すれば、以下のように新しいproductが作成できるようになるはずです。
{
"product": {
"product_name": "Ruby Programming 101",
"product_price": "15.00"
"product_image": "http://link-to-image-url/image.jpg"
}
}
しかしクライアントリクエストのbodyにあるキーバリューペアが以下のように異なっている場合はどうすればよいでしょうか。
{
"product": {
"name": "Ruby Programming 101",
"price": "15.00"
"image": "http://link-to-image-url/image.jpg"
}
}
改修前
Rails 7より前は、strong parametersのキーを変更してから、コントローラ内でキーの値を1つずつ変更する方法で解決したりしていたでしょう。
class ProductsController < ApplicationController
def create
params = product_params
@product = Product.new
@product.product_name = params[:product][:name]
@product.product_price = params[:product][:price]
@product.product_image = params[:product][:image]
respond_to do |format|
# HTMLとJSONでレスポンスを返す
end
end
private
# 信頼できるパラメータリストのみ受け取りを許可する
def product_params
params.require(:product).permit(:name, :price, :image)
end
end
この方法だと手動更新が多数必要になるのが残念です。
改修後
Rails 7では、パラメータオブジェクトでto_h
を呼び出して標準のハッシュに置き換えてからキーをコントローラ内で変更できるようになりました。これにより、多くの手動更新を必要とせずにパラメータをインテリジェントに扱えるようになります。to_h
はパラメータオブジェクトの振る舞いを一切変更しないので、パラメータオブジェクトの変更は不要です。
class ProductsController < ApplicationController
def create
@product = Product.new(product_params)
respond_to do |format|
# HTMLとJSONでレスポンスを返す
end
end
private
# 信頼できるパラメータリストのみ受け取りを許可する
def product_params
params.require(:product)
.permit(:name, :price, :image)
.to_h { |key, value| [:"product_#{key}", value] }
end
end
このソリューションはコードが明快でロジックも理解しやすいので、よりRails wayらしく感じられます。
上の例はActionController::Parameters
のto_h
の活用法のひとつに過ぎません。params
ハッシュの値を以下のように変更することも可能です。
params = ActionController::Parameters.new(language: "Ruby", framework: "Ruby on Rails", version: "7.0.1")
params.to_h { |key, value| [key, "#{value == "Ruby" ? "Best Programming language on Earth" : value}"] }
#=> {"language"=>"Best Programming language on Earth", "framework"=>"Ruby on Rails", "version"=>"7.0.1"}
編集部注
上のサンプルコードはpermit
が省略されているのでそのままではActionController::UnfilteredParameters
エラーになります。
参考: Rails API to_h
-- ActionController::Parameters
詳しくは#44756を参照してください。
概要
元サイトの許諾を得て翻訳・公開いたします。
#44756は、現時点ではmainブランチにのみ含まれており、7-0-stableブランチには含まれていません。
参考: 週刊Railsウォッチ20220328
ActionController::Parameters.to_h
にブロックを渡せるようになった