Rails 7 allows permitting numeric params

In Rails, strong params provide an interface for protecting attributes from the end-user assignment. We can specify required attributes and neglect unnecessary attributes to be used in the Active model mass assignment. However, in Rails 6, there was an issue with permitting nested hash with numeric keys. Permit behavior was inconsistent and confusing when nested hash contains integer keys.

Let’s understand this by an example. Here, we have params with numeric keys.

params = ActionController::Parameters.new(
  person: {
    "0": {
      name: "Sam",
      email: "sam@example.com"
    "1": {
      name: "John",
      email: "john@example.com"

params.require(:person).permit("0": [:name], "1": [:name]).to_h

# {"0"=>{"name"=>"Sam"}, "1"=>{"name"=>"John"}}

The params can be permitted as we did above. This is what we want in most cases but issues arise when we call permit directly on parent hash.


We can permit individual keys under numeric keys by specifying them for each numeric key.

params.require(:person).permit("0": [:name], "1": [:email]).to_h

# {"0"=>{"name"=>"Sam"}, "1"=>{"email"=>"john@example.com"}}

It returns the keys that we specified individually for each numeric key.

However, when we call permit directly on parent hash i.e without using require, the result is not the same anymore.

params.permit(person: {"0": [:name], "1": [:email]}).to_h

# {"person"=>{"0"=>{}, "1"=>{}}}


In Rails 7, the issue with the permit method has been resolved. Now, the permit behaves same as calling on parent hash as calling on child hash.

We can see in the below example that calling the permit method directly on params gets the same result as first calling require on params and then permitting the required attributes.

params.require(:person).permit("0": [:name], "1": [:email]).to_h

# {"0"=>{"name"=>"Sam"}, "1"=>{"email"=>"john@example.com"}}

params.permit(person: {"0": [:name], "1": [:email]}).to_h

# {"person"=>{"0"=>{"name"=>"Sam"}, "1"=>{"email"=>"john@example.com"}}}

Check out this pull request to know more about this change.

Join Our Newsletter