How to permit hash with rails strong params

Viewed 1558

I am working on a Model with an atter_accessor object named element. I want to pass the Array of form data to the element object. In Rails console I am getting Unpermitted parameter error.

Parameters: {"authenticity_token"=>"[FILTERED]", "category"=>{"name"=>"asfd", "body"=>"asf", "element"=>{"1"=>"asfd:text", "2"=>"asfd:text", "3"=>"asfd:text"}}, "type"=>"text", "commit"=>"Create Category"}
Unpermitted parameter: :element. Context: { controller: CategoriesController, action: create, request: #<ActionDispatch::Request:0x0000000106b3ff68>, params: {"authenticity_token"=>"[FILTERED]", "category"=>{"name"=>"asfd", "body"=>"asf", "element"=>{"1"=>"asfd:text", "2"=>"asfd:text", "3"=>"asfd:text"}}, "type"=>"text", "commit"=>"Create Category", "controller"=>"categories", "action"=>"create"} }

In model attr_accessor :elements

In controller

def category_params
  params.require(:category).permit(:name, :body, :elements => []) 
end

I tried with many alternatives changing the :elements to element: [] too, nothing worked. I think I am missing something here which is the reason I am getting an unpermitted parameters.

2 Answers

You haven't mentioned the version of rails you are using but, :elements => [] does not work because elements is a ruby hash and not an array

on rails 5.1+ you can use

params.require(:category).permit(:name, :body, :elements => {}) 

A lot of confusion going on here besides the element / elements naming issue - pick one and stick with it.

If you want to pass an array as FormData in Rack applications you need to use keys with empty brackets:

irb(main):001:0> str = "elements[]=a&elements[]=b&elements[]=c"                                                         => "elements[]=a&elements[]=b&elements[]=b"
irb(main):002:0> Rack::Utils.parse_nested_query(str)                                                                   
=> {"elements"=>["a", "b", "c"]}   

If you place any sort of value in the brackets it will be parsed as a hash instead:

irb(main):003:0> str = "elements[1]=a&elements[2]=b&elements[3]=c"
=> "elements[1]=a&elements[2]=b&elements[3]=b"
irb(main):004:0> Rack::Utils.parse_nested_query(str)
=> {"elements"=>{"1"=>"a", "2"=>"b", "3"=>"c"}}    

When whitelisting an empty array will permit an array of permitted scalar values:

irb(main):005:0> params = ActionController::Parameters.new(Rack::Utils.parse_nested_query("elements[]=a&elements[]=b&elements[]=b"))
=> #<ActionController::Parameters {"elements"=>["a", "b", "b"]} permitted: false>
irb(main):006:0> params.permit(elements: [])
=> #<ActionController::Parameters {"elements"=>["a", "b", "b"]} permitted: true> 

When whitelisting hashes you pass an array of symbols which represent the keys you want to permit:

irb(main):006:0> params = ActionController::Parameters.new(foo: { bar: 1, baz: 2, woo: 3 })
irb(main):007:0> params.permit(foo: [:bar, :baz])
=> #<ActionController::Parameters {"foo"=>#<ActionController::Parameters {"bar"=>1, "baz"=>2} permitted: true>} permitted: true>

You can also permit a hash with arbitrary keys by passing an empty hash:

irb(main):008:0> params.permit(foo: {})
=> #<ActionController::Parameters {"foo"=>#<ActionController::Parameters {"bar"=>1, "baz"=>2, "woo"=>3} permitted: true>} permitted: true>  

This is a somewhat dangerous operation and should be done with care.

Related