Rails - Strong Parameters - Nested Objects

Ruby on-RailsNested AttributesStrong Parameters

Ruby on-Rails Problem Overview


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?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

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

Solution 2 - Ruby on-Rails

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

Solution 3 - Ruby on-Rails

Permitting a nested object :

params.permit( {:school => [:id , :name]}, 
               {:student => [:id, 
                            :name, 
                            :address, 
                            :city]},
                {:records => [:marks, :subject]})

Solution 4 - Ruby on-Rails

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBenjamin MView Question on Stackoverflow
Solution 1 - Ruby on-Railsj03wView Answer on Stackoverflow
Solution 2 - Ruby on-RailsM.ElSakaView Answer on Stackoverflow
Solution 3 - Ruby on-RailsCodieeView Answer on Stackoverflow
Solution 4 - Ruby on-Railsuser8164115View Answer on Stackoverflow