Rails Unable to Convert Unpermitted Parameters to Hash

Rails Unable to convert unpermitted parameters to hash

In Rails 5, ActionController::Parameters no longer inherits from Hash, in an attempt to discourage people from using Hash-related methods on the request parameters without explicitly filtering them.

As part of this pull request, which was backported into Rails 5.1 and partially into Rails 5.0, an exception is raised if you try to call to_h on the parameters object without calling permit.

Calling merge on the original params object (params.merge(:sort => column, :direction => direction, :page => nil)) returns a new ActionController::Parameters object with the same permitted status (that is, permit has not been called on it). The link_to method then ends up calling to_h on that object, which raises the exception.

If you know which parameters should be allowed in the link, you can call permit with those listed.

params.permit(:param_1, :param_2).merge(:sort => column, :direction => direction, :page => nil)
# OR
params.merge(:sort => column, :direction => direction, :page => nil).permit(:param_1, :param_2, :sort, :direction, :page)

If you don't know which parameters could be included in the link, then it's possible to call request.parameters.merge(...) (as mentioned in this answer) or params.to_unsafe_h.merge(...). However, as pointed out in comments, this is a security risk when the result is passed to link_to, as a parameter like host would be interpreted as the actual host for the link instead of a query parameter. There are several other keys that also have special meaning in link_to (everything accepted by url_for, plus :method), so it's generally a risky approach.

Unable to convert unpermitted parameters to hash - Ruby on Rails app error

Through much searching I found it it was a gem causing the error after updating Rails to 5.1. Using the 'canonical-rails' gem and using the line <%= canonical_tag -%> for some reason was causing this error. Couldn't tell you why, but hopefully this will help anyone else that comes across it.

Unable to convert unpermitted parameters to hash

So I was able to solve this from the model and in the controller:

I still had

attr_accessor

while also having params in private. I removed this, and also in the controller I changed the line of code from this:

session[:zerch_params].deep_merge!(params[:zerch]) if params[:zerch]

to this:

session[:zerch_params].deep_merge!(params.permit![:zerch]) if params[:zerch]

ActionController::UnfilteredParameters (unable to convert unpermitted parameters to hash) - Rails 5

You created the method user_params, but in the register action you are using params (that is, unfiltered parameters).

So change this:

def register
ap params
end

to this:

def register
ap user_params
end

Why am I getting strong parameter errors in the Rails Console in rails 5?


What's Happening and Why

ActionController::Parameters (which is what params works with in controllers) used to inherit from HashWithIndifferentAccess which inherits from Hash. So ActionController::Parameters < Hash used to be true as would something like:

params.require(:x).permit(some_hash: %i[key1 key2]).is_a? Hash

If you were digging a Hash out of params:

some_hash = params.require(:x).permit(some_hash: ...)

and serializing that in a model:

class M < ApplicationRecord # Or ActiveRecord::Base in the past
serialize :h, Hash
end
#...
m.h = some_hash

you could end up with some YAML like this in your database:

--- !ruby/object:ActionController::Parameters
...

rather than the expected plain YAMLized hash.

But then Rails5 comes along and ActionController::Parameters no longer inherits from Hash:

  • Make ActionController::Parameters no longer inherits from HashWithIndifferentAccess.

and calling to_h or to_hash on an ActionController::Parameters now raises an exception.

If you upgrade your code and try to load a model with serialized data in it:

serialize :h, Hash

then the model will load the text from h, parse the YAML to get an ActionController::Parameters instance, and call to_h on it to make sure it has a Hash, and you get an exception.

What To Do About It

There are a couple things you need to do:

  1. Fix your controllers to make sure they get real hashes out of params.
  2. Fix your data so that you have serialized hashes rather than ActionController::Parameters instances.

Fixing the controllers is a simple matter of calling to_unsafe_h on the parameters that aren't yet real hashes.

Fixing the data is uglier. I'd probably go through the tables using the low level database interface (i.e. no ActiveRecord anywhere), read the YAML out from each row, YAML.load it, convert it to a hash by calling to_unsafe_h on it, and then writing back the_real_hash.to_yaml text. You could use a like '--- !ruby/object:ActionController::Parameters%' filter in the WHERE clause to only deal with the broken rows.

I'd also strongly recommend that you stop using serialize while you're there. serialize is a bit of a kludge and there's no sane way to work with YAML inside the database; there's also little need for it now that both PostgreSQL and MySQL have native JSON support (but I'm not sure how well ActiveRecord supports MySQL's JSON).



Related Topics



Leave a reply



Submit