Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions actionpack/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,16 @@

*Julian Nadeau*

* Add support for strong parameter to deal with nested arrays

Strong parameters doesn't support nested arrays,
take as example: `[[{ name: 'Leonardo', age: 26 }]]`.

This is fixed adding a method that is called when object is an array, and recursively returns allowed values.


Fixes #23640.

*Leonardo Siqueira*

Please check [5-1-stable](https://github.com/rails/rails/blob/5-1-stable/actionpack/CHANGELOG.md) for previous changes.
26 changes: 25 additions & 1 deletion actionpack/lib/action_controller/metal/strong_parameters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -845,10 +845,34 @@ def convert_value_to_parameters(value)
end
end

def permit_nested_array(elements, object)
permitted = []

object.each do |nested_object|
case nested_object
when Array
permitted << permit_nested_array(elements, nested_object)
when Hash, ActionController::Parameters
permitted << nested_object.select { |nested| elements.keys.include?(nested) }
else
permitted << nested_object if object.include?(nested_object)
end
end

permitted
end

def each_element(object)
case object
when Array
object.grep(Parameters).map { |el| yield el }.compact
allowed_elements = object.flatten.grep(Parameters).map { |el| yield el }.compact

if object.first.is_a?(Array)
permit_nested_array(allowed_elements.first, object)
else
allowed_elements
end

when Parameters
if object.fields_for_style?
hash = object.class.new
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ def assert_filtered_out(params, key)
params = ActionController::Parameters.new(
book: {
title: "Romeo and Juliet",
sections: [[{
title: "Romance",
description: "A Romance section"
}]],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this array had two sections I'd expect both sections to be permitted but only the first one is.

Also, I think this syntax is ambiguous.

Given params.permit(sections: [[[:title]]]), what would be result for the following hashes ?

         sections: [
          [
            {
              title: "romance",
              description: "a romance section"
            }
          ],
          [
            {
              title: "drama",
              description: "a drama section"
            }
          ]
        ],

And

        sections: [
          [
            {
              title: "romance",
              description: "a romance section"
            },
            {
              title: "drama",
              description: "a drama section"
            }
          ]
        ],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would permit both

pages: [[1]],
reviews: [[[
{ title: "Awesome book", description: "It's an awesome book" },
{ title: "So good", description: "This book is so good" }
],
{ title: "Don't like", description: "I prefer Hamlet" }
]],
authors: [{
name: "William Shakespeare",
born: "1564-04-26"
Expand All @@ -30,10 +41,21 @@ def assert_filtered_out(params, key)
},
magazine: "Mjallo!")

permitted = params.permit book: [ :title, { authors: [ :name ] }, { details: :pages }, :id ]
permitted = params.permit book: [ :title, { authors: [ :name ] }, { details: :pages }, :id, sections: [[[:title]]], reviews: [[[[:title, :description]]]], pages: [[]] ]

assert permitted.permitted?
assert_equal "Romeo and Juliet", permitted[:book][:title]

assert_equal [1], permitted[:book][:pages][0]
assert_equal "Romance", permitted[:book][:sections][0][0][:title]
assert_nil permitted[:book][:sections][0][0][:description]
assert_equal "Awesome book", permitted[:book][:reviews][0][0][0][:title]
assert_equal "It's an awesome book", permitted[:book][:reviews][0][0][0][:description]
assert_equal "So good", permitted[:book][:reviews][0][0][1][:title]
assert_equal "This book is so good", permitted[:book][:reviews][0][0][1][:description]
assert_equal "Don't like", permitted[:book][:reviews][0][1][:title]
assert_equal "I prefer Hamlet", permitted[:book][:reviews][0][1][:description]

assert_equal "William Shakespeare", permitted[:book][:authors][0][:name]
assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name]
assert_equal 200, permitted[:book][:details][:pages]
Expand Down