Reputation: 1608
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.
Upvotes: 43
Views: 77228
Reputation: 3611
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."
Upvotes: 19
Reputation: 4320
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.
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
Upvotes: 88
Reputation: 6981
Word to the wise: if you're using link_to_sorted
from the sorted gem it breaks views in Rails 5.
Upvotes: 0
Reputation: 3282
I think what's happening is the following:
In a console you are working with a simple hash called attributes
. As a hash the attributes
parameter in the console has a valid instance method called values
.
In your rails app the params hash is not a simple hash any more. It is an instance of the ActionController::Parameters
class. As an instance of that class it does not have an instance method called values
, but it does have an instance method called to_h
& to_unsafe_h
, which would accomplish your goals. After calling to_h
on your parameters you can call the values
method.
Upvotes: 3