How to permit hash with rails strong params
Asked Answered
N

2

5

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.

Nash answered 19/2, 2022 at 4:46 Comment(5)
I’m not sure with this, but you can try params.permit(:name, :body, element: [])Kerriekerrigan
I tried, didn't worked. Am I going the wrong way!.Nash
how about params.permit(:name, :body, :element) ?Kerriekerrigan
I don't think this will work! It will return unpermitted parameters exception for all fields.Nash
I’m sorry that I can’t help you with this, but I recommend you to change the attr_accessor :element to attr_accessor :elements so that your team work or other people who read your question will not misunderstandingKerriekerrigan
I
7

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 => {}) 
Incommensurable answered 19/2, 2022 at 5:34 Comment(8)
Great, I was missing this. ThanksNash
This isn't quite correct. Nested parameters are actually instances of ActionController::Parameters and parameters whitelisting isn't some some case of an equity check.Sneeze
@Sneeze I never claimed it was an equality check. Just showing the OP how to fix their problem.Incommensurable
Is it possible to specify the permitted hash keys inside elements?Francesco
is it safe todo? since its accept whatever hash the elements have?Christianechristiania
@Sneeze what do you mean by that max?Christianechristiania
@Francesco yes it's possible to have nested objects in the strong params. Check out this answer #18437241Incommensurable
@Christianechristiania generally speaking it's not a good idea, but it can depend on the application and the context. Sometimes when incoming json structure is dynamic there's almost no choice but to allow all keys. If possible you should avoid a blanket {}Incommensurable
S
0

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.

Sneeze answered 19/2, 2022 at 16:35 Comment(1)
it's kinda confusing, so in strong parameters the bracket doesn't mean the parameters comes in array/multiples, to make ruby/rails know that your parameters is array/multiple you need to add bracket with index into it more read hereChristianechristiania

© 2022 - 2024 — McMap. All rights reserved.