Rails - Strong Parameters - Nested Objects
Asked Answered
W

4

166

I've got a pretty simple question. But haven't found a solution so far.

So here's the JSON string I send to the server:

{
  "name" : "abc",
  "groundtruth" : {
    "type" : "Point",
    "coordinates" : [ 2.4, 6 ]
  }
}

Using the new permit method, I've got:

params.require(:measurement).permit(:name, :groundtruth)

This throws no errors, but the created database entry contains null instead of the groundtruth value.

If I just set:

params.require(:measurement).permit!

Everything get's saved as expected, but of course, this kills the security provided by strong parameters.

I've found solutions, how to permit arrays, but not a single example using nested objects. This must be possible somehow, since it should be a pretty common use case. So, how does it work?

Waki answered 26/8, 2013 at 4:43 Comment(2)
have a look into this #14484463Palmirapalmistry
@vinodadhikary It was correct… I think the OP is confused. As odd as it sound when you want to permit nested attributes you do specify the attributes of nested object within array. On the other hand if you want nested of multiple objects then you wrap it inside a hash… see api.rubyonrails.org/classes/ActionController/… and github.com/rails/rails/blob/master/actionpack/lib/…Jeanninejeans
J
204

As odd as it sound when you want to permit nested attributes you do specify the attributes of nested object within an array. In your case it would be

Update as suggested by @RafaelOliveira

params.require(:measurement)
      .permit(:name, :groundtruth => [:type, :coordinates => []])

On the other hand if you want nested of multiple objects then you wrap it inside a hash… like this

params.require(:foo).permit(:bar, {:baz => [:x, :y]})


Rails actually have pretty good documentation on this: http://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-permit

For further clarification, you could look at the implementation of permit and strong_parameters itself: https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/strong_parameters.rb#L246-L247

Jeanninejeans answered 26/8, 2013 at 5:59 Comment(5)
both cases are the same in this answer, actually, it's just that the curly brackets are optional around { :groundtruth => [...]}; It's a hash but the interpreter is able to determine where the hash begins and ends without explicit curly brackets.Surcease
Nested arrays of attributes do not allow nested attributes. Nested attributes and attr_accessor are listed in my application as "Unpermitted parameters". Still looking for safe solution.Remorseless
In case of multiple nested objects, you should also permit the id for this to work. More info here : #18309214Persimmon
This only permits ONE set of nested attributes. This will not work in the case of a one to many.Brahmaputra
@Surcease if that's the case I suspect it's better practice to keep the curly brackets so the reader of the code has a clearer understanding of what's going onPneumococcus
G
26

I found this suggestion useful in my case:

  def product_params
    params.require(:product).permit(:name).tap do |whitelisted|
      whitelisted[:data] = params[:product][:data]
    end
  end

Check this link of Xavier's comment on github.

This approach whitelists the entire params[:measurement][:groundtruth] object.

Using the original questions attributes:

  def product_params
    params.require(:measurement).permit(:name, :groundtruth).tap do |whitelisted|
      whitelisted[:groundtruth] = params[:measurement][:groundtruth]
    end
  end
Girt answered 29/6, 2014 at 11:21 Comment(4)
Just a side note, This will still show in the log as unpermitted parameters but the model will accept them anyways.Siesta
Not sure of Rails 4 but in my Rails 5 project I have to call permit! to be whitelisted or else it's remained unpermitted after tapping it. In this case it would be params[:measurement][:groundtruth].permit!Pernambuco
@Pernambuco i also get the unpermitted message but adding permit! raises this error NoMethodError (undefined method permit!' for #<Array:0x007f80cb71ea00>):`Cheat
@Cheat permit! method is not available in Array. You'll need to have access to the respective class instance to have access to permit! (it's been a while so I've forgotten the class name but it's something like ActionController::Parameters based on this page).Pernambuco
R
13

Permitting a nested object :

params.permit( {:school => [:id , :name]}, 
               {:student => [:id, 
                            :name, 
                            :address, 
                            :city]},
                {:records => [:marks, :subject]})
Retrieval answered 30/3, 2016 at 8:16 Comment(0)
M
3

If it is Rails 5, because of new hash notation: params.permit(:name, groundtruth: [:type, coordinates:[]]) will work fine.

Morsel answered 1/11, 2018 at 16:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.