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 fromHashWithIndifferentAccess
.
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:
- Fix your controllers to make sure they get real hashes out of
params
. - 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
How to Create an Anchor and Redirect to This Specific Anchor in Ruby on Rails
Which Ruby Version am I Really Running
Handling Exceptions Raised in a Ruby Thread
What Exactly "Config.Assets.Debug" Setting Does
Ruby Timeouts and System Commands
Rails: How to Get Has_Many Associations of a Model
How to Calculate How Many Years Passed Since a Given Date in Ruby
How to Get a Particular Line from a File
How to Test CSV File Download in Capybara and Rspec
How to Test 'Rand()' with Rspec
How to Change Column Type in Heroku
Convert String into Array in Rails
How to Get Past "Http://Gems.Rubyforge.Org/ Does Not Appear to Be a Repository" Error Message