Rails ActionController::Parameters
are a convenient way to pass data from a request to a controller action.
Every request made to a controller action with parameters should be handled with utmost caution.
ActionController::Parameters
is a convenient way to do that.
With Rails 7, we can now convert an ActionController::Parameters
object to a standard Hash using the .to_h
method.
This is great news for developers who want to customize
the way their data is passed to the controller.
This also means we can change the behavior of the parameters
without having to change anything on the client code.
Let’s assume we have scaffolded a Product model with product_name
,
product_price
,
and product_image
as attributes.
class ProductsController < ApplicationController
def create
@product = Product.new(product_params)
respond_to do |format|
# respond to HTML, JSON
end
end
private
# Only allow a list of trusted parameters through.
def product_params
params.require(:product).permit(:product_name, :product_price, :product_image)
end
end
Now, if the frontend app sends an appropriate request with appropriate parameters, we should be able to create a new product.
{
"product": {
"product_name": "Ruby Programming 101",
"product_price": "15.00"
"product_image": "http://link-to-image-url/image.jpg"
}
}
But, what if the client’s request body has different key/value pairs?
{
"product": {
"name": "Ruby Programming 101",
"price": "15.00"
"image": "http://link-to-image-url/image.jpg"
}
}
Before
Before Rails 7, the way to solve this would be to change strong params keys and then modify the keys one by one inside the controller.
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|
# respond to HTML, JSON
end
end
private
# Only allow a list of trusted parameters through.
def product_params
params.require(:product).permit(:name, :price, :image)
end
end
There are a lot of manual updates that are needed in this case which does not feel like a good practice.
After
Instead, with Rails 7, we can use the to_h
method on the parameters object
to convert it to a standard Hash and then make changes to the keys inside the controller.
This allows us to handle parameters more intelligently without requiring a lot of manual updates.
The to_h
method doesn’t change the behavior of the parameters object at all,
so there is no need to modify it in any way.
class ProductsController < ApplicationController
def create
@product = Product.new(product_params)
respond_to do |format|
# respond to HTML, JSON
end
end
private
# Only allow a list of trusted parameters through.
def product_params
params.require(:product)
.permit(:name, :price, :image)
.to_h { |key, value| [:"product_#{key}", value] }
end
end
This solution looks and feels a lot like the Rails way. Clean code with easy to understand logic!
The above example is just one way of using the .to_h
method with ActionController::Parameters,
we can also modify the values of the params
hash to be.
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"}
Check out the PR for more details.