How to permit nested parameters in Rails

The context

Rails 5 introduced a big change in how it handles ActionController::Parameters (the parameters that you get on your Controllers): before Rails 5, if you called your params you would get a hash back and after Rails 5, you get a ActionController::Parameters object. You can see that by calling params.inspect and if you call .to_h on these parameters you should be good to go.

However, you might get an empty hash when calling .to_h on some parameters because they were not explicitly permitted – see the result of inspecting my params (note the “permitted: false” at the very end):

<ActionController::Parameters {"friends" => {"park" => "Doggoland", "dogs"=>[ {"id"=>73, "name"=>"Milou", "household"=>"Tintin"},   {"id"=>74, "name"=>"Snoopy", "household"=>"Charlie Brown"}]}} permitted: false>

Permitting params was showing up back in Rails 4 when Strong Parameters were introduced as part of security features and this blog post goes through some examples of why just calling .to_h might be an issue now that Rails 5 returns objects instead.

Permitting parameters

One good way to permit some parameters is by creating a private helper function in your controller that will explicitly permit the parameters you want:

private
def nice_params
  params.permit(:id, :name, :email).to_h
end

When accessing your params, instead of params[:name], you use nice_params[:name].

Permitting nested parameters

Things get a little more complicated when you have a nested data structure. The documentation only gets one level deep and I had something more complicated than that. Let’s use the following as an example:

{"friends" => {
  "park" => "Doggoland",
  "dogs"=>[
    {"id"=>73, "name"=>"Milou", "household"=>"Tintin"}, 
    {"id"=>74, "name"=>"Snoopy", "household"=>"Charlie Brown"}
   ]
  }
}

My nice_params function looks like this:

def nice_params
  params.permit(
    friends: [:park, dogs: [:id, :name, :household]]
  ).to_h
end

One very important thing to notice is that the nested list must be placed last!

I hope this helps someone else with deep nested params. 😅


If you found this helpful, let me know on Twitter!

The post How to permit nested parameters in Rails was originally published at flaviabastos.ca