Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 5: unable to retrieve hash values from parameter

I'm running into a strange issue.

undefined method `values' for #<ActionController::Parameters:0x007fb06f6b2728>

is the error I get, when I assign a variable to a param hash, and try to get it's values.

attributes = params[:line_item][:line_item_attributes_attributes] || {}
attributes.values

the parameter looks like this a hash of hashes:

{"0"=>{"product_attribute_id"=>"4"}, "1"=>{"product_attribute_id"=>"7"}}

now when I do this in console and assign that to a variable attributes it works flawlessly. So I'm struggling to understand what isn't working here - and how to make it work.

like image 860
Sebastian Jennings Almnes Avatar asked Jan 22 '16 14:01

Sebastian Jennings Almnes


2 Answers

take a look to this. Very weird since ActionController::Parameters is a subclass of Hash, you can convert it directly to a hash using the to_h method on the params hash.

However to_h only will work with whitelisted params, so you can do something like:

permitted = params.require(:line_item).permit(: line_item_attributes_attributes)
attributes = permitted.to_h || {}
attributes.values

But if instead you do not want to whitelist then you just need to use the to_unsafe_h method.

Update

I was very curious about this issue, so I started researching, and now that you clarified that you are using Rails 5, well that's the cause of this issue, as @tillmo said in stable releases of Rails like 4.x, ActionController::Parameters is a subclass of Hash, so it should indeed respond to the values method, however in Rails 5 ActionController::Parameters now returns an Object instead of a Hash

Note: this doesn’t affect accessing the keys in the params hash like params[:id]. You can view the Pull Request that implemented this change.

To access the parameters in the object you can add to_h to the parameters:

params.to_h

If we look at the to_h method in ActionController::Parameters we can see it checks if the parameters are permitted before converting them to a hash.

# actionpack/lib/action_controller/metal/strong_parameters.rb
def to_h
  if permitted?
    @parameters.to_h
  else
    slice(*self.class.always_permitted_parameters).permit!.to_h
  end
end

for example:

def do_something_with_params
  params.slice(:param_1, :param_2)
end

Which would return:

{ :param_1 => "a", :param_2 => "2" }

But now that will return an ActionController::Parameters object.

Calling to_h on this would return an empty hash because param_1 and param_2 aren’t permitted.

To get access to the params from ActionController::Parameters, you need to first permit the params and then call to_h on the object

def do_something_with_params
  params.permit([:param_1, :param_2]).to_h
end

The above would return a hash with the params you just permitted, but if you do not want to permit the params and want to skip that step there is another way using to_unsafe_hash method:

def do_something_with_params
  params.to_unsafe_h.slice(:param_1, :param_2)
end

There is a way of always permit the params from a configuration from application.rb, if you want to always allow certain parameters you can set a configuration option. Note: this will return the hash with string keys, not symbol keys.

#controller and action are parameters that are always permitter by default, but you need to add it in this config.
config.always_permitted_parameters = %w( controller action param_1 param_2)

Now you can access the params like:

def do_something_with_params
  params.slice("param_1", "param_2").to_h
end

Note that now the keys are strings and not symbols.

Hope this helps you to understand the root of your issue.

Source: eileen.codes

like image 198
svelandiag Avatar answered Oct 15 '22 12:10

svelandiag


Since Rails 5, params are of class 'ActionController::Parameters'

If you do params.to_h you will get the following error.

*** ActionController::UnfilteredParameters Exception: unable to convert 
unpermitted parameters to hash

You can do as follows to permit all the params and get as Hash format:

parameters = params.permit(params.keys).to_h

"But beware of using this! You are permitting all the params which may include unknown params that can harm your code."

like image 16
Abhi Avatar answered Oct 15 '22 13:10

Abhi