Params Wrapper in Ruby on Rails Explained
Auto wrap parameters in a nested hash to simplify requests

If you’ve ever wondered why sending this in your request.
{"name":"Coffee & Code", "location":"Chelsea"}
Becomes this in your controller params
.
{
"name" => "Coffee & Code",
"location" => "Chelsea",
"meetup" => {
"name" => "Coffee & Code",
"location" => "Chelsea"
}
}
It’s because of ParamsWrapper
.
Note how “name”
and “location”
exist twice, once inside “meetup”
and once outside.
A Quick Demonstration
Let’s create a simple Rails app and review how params
changes with and without ParamsWrapper
.
Create a new Rails app on the command line.
$ rails new params_app --api --skip-unit-test --database=postgres
Add a controller called /controllers/meetups_controller.rb
, and paste in the following.
class MeetupsController < ApplicationController
def create
render json: {}, status: 200
end
end
Edit /config/routes.rb
.
Rails.application.routes.draw do
post "meetups", to: "meetups#create"
end
And make a request from the command line.
curl -XPOST http://localhost:3000/meetups \
-H 'Content-Type: application/json' \
-d '{"name":"Coffee & Code", "location":"Chelsea"}'
The Rails server logs will now display below.
Started POST "/meetups" for ::1 at 2020-09-29 12:11:40 -0400
Processing by MeetupsController#create as */*
Parameters: {
"name"=>"Coffee & Code",
"location"=>"Chelsea",
"meetup"=>{
"name"=>"Coffee & Code",
"location"=>"Chelsea"
}
}
Completed 200 OK in 0ms (Views: 0.1ms | ActiveRecord: 0.0ms | Allocations: 139)
We didn’t specify a “meetup”
key/value in the request, so how did it get there?
ActiveRecord’s ParamsWrapper
did that automatically. It’s default behavior is to wrap requests in a nested hash, based on the name of the resource.
Turn ParamsWrapper Off
The default is set in /initializers/wrap_parameters.rb
.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json]
end
But it can be turned off by changing [:json]
to []
in the initializer, or inside a specific controller.
After deactivating, controller params
look like this.
{
"name"=>"Coffee & Code",
"location"=>"Chelsea"
}
The Benefit of ParamsWrapper
It allows you to send requests like this.
{"name":"Coffee & Code", "location":"Chelsea"}
Instead of this.
{"meetup": {"name":"Coffee & Code", "location":"Chelsea"}}
Strong params (see below), requires the root element “meetup”
, so this makes it slightly easier on the requester.
params.require(“meetup”).permit(“name”, “location”)
That said, the net benefit is debatable given the ambiguity it adds, but that’s Rails for you :)
I hope you found this useful. Let me know if you have related questions!
Rails 6.0.3.2 was used for the above code.