Strong parameters and multidimensional arrays

2019-04-08 18:05发布

问题:

I'm using Rails 3.2.6 with strong parameters gem.

So, I' have a controller with the typical update action:

# PUT /api/resources/:id
def update
  @resource.update_attributes! permited_params
  respond_with_json @resource, action: :show
end

Then, I have the permited_params method

def permited_params
  params.permit(:attr1, :attr2, :attr3)
end

The problem is that :attr3 is a multidimensional array like this: [[1, 2], [2, 5, 7]]

Following the documentation, I need to specify :attr3 as an array. But...

params.permit(:attr1, :attr2, :attr3 => [])
#inspecting permited_params: {"attr1"=>"blah", "attr2"=>"blah"}

params.permit(:attr1, :attr2, :attr3 => [[]])
#inspecting permited_params: {"attr1"=>"blah", "attr2"=>"blah", "attr3" => []}

params.permit(:attr1, :attr2, :attr3 => [][])
#throw error

The question is: How can I use strong params with multidimensional arrays?

回答1:

You can also do this in this way

   def permited_params
     hash = params.permit(:attr1, :attr2) 
     hash[:attr3] = params.require(:attr3) if params.has_key?(:attr3)
     hash
   end


回答2:

I was seeing this type of question many times so i though to dig into the code and find the reason and make it work.

It turns around that whatever written in documentation is correct. This is from strong parameter documentation.

The permitted scalar types are String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch::Http::UploadedFile and Rack::Test::UploadedFile.

This scalar values are inside stored in ::ActionController::Parameters::PERMITTED_SCALAR_TYPE

If you see its value, you will find that it doesn't accept Array as value .

To make this work, all you need to do to add Array into whitelist, i.e if you do

::ActionController::Parameters::PERMITTED_SCALAR_TYPE << Array

it will work. But this is bad solution. I'm not the strong_parameter contributor so i am not aware of security risks. So, to solve this problem all you have to do is to include method in your controller something like this

def allow_array_in_strong_parameter
  old_scalar_types = ::ActionController::Parameters::PERMITTED_SCALAR_TYPES.dup
  ::ActionController::Parameters::PERMITTED_SCALAR_TYPES << Array
  params.permit(:attr1, :attr2, :attr3 => [])
  ::ActionController::Parameters::PERMITTED_SCALAR_TYPES = old_scalar_types
end