问题
I want to call this in my console (ap
is the awesome print gem):
ap Purchase.last(10)
but I get this error:
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
It works like this:
irb(main):020:0> ap Purchase.last
#<Purchase:0x00007f86b792a320> {
:id => 28445,
:user_id => 10177,
:product_id => nil,
:product_type => nil,
:price => 9.0,
:gateway_code => nil,
:gateway_msg => nil,
:gateway_response => nil,
:created_at => Fri, 18 May 2018 22:20:10 UTC +00:00,
:updated_at => Fri, 18 May 2018 22:20:10 UTC +00:00,
:checkout_total => 9.0,
:successful => true,
:cart_id => 17242,
:report_errors => nil,
:transacted_value_of_products => 9.0,
:comp_credits_applied => 0.0
}
And without ap
like this:
irb(main):022:0> Purchase.last(10)
D, [2018-05-25T20:58:54.692575 #70552] DEBUG -- : Purchase Load (0.5ms) SELECT "purchases".* FROM "purchases" ORDER BY "purchases"."id" DESC LIMIT $1 [["LIMIT", 10]]
+-------+---------+------------+-------------+-------+-------------+-------------+-------------+-------------+--------------+-------------+------------+---------+-------------+-------------+-------------+
| id | user_id | product_id | product_... | price | gateway_... | gateway_msg | gateway_... | created_at | updated_at | checkout... | successful | cart_id | report_e... | transact... | comp_cre... |
+-------+---------+------------+-------------+-------+-------------+-------------+-------------+-------------+--------------+-------------+------------+---------+-------------+-------------+-------------+
| 28436 | 10471 | | | 5.0 | | Completed | {"mc_gro... | 2018-05-... | 2018-05-1... | 5.0 | true | 17228 | {} | 5.0 | 0.0 |
| 28437 | 9754 | | | 1.99 | | Completed | {"mc_gro... | 2018-05-... | 2018-05-1... | 2.48 | true | 15273 | {} | 1.99 | 0.0 |
| 28438 | 10472 | | | 9.0 | | | {\n "id... | 2018-05-... | 2018-05-1... | 9.0 | true | 17231 | {} | 9.0 | 0.0 |
| 28439 | 10348 | | | 9.0 | | | | 2018-05-... | 2018-05-1... | 9.0 | true | 17235 | | 9.0 | 0.0 |
But not with an argument and ap
irb(main):021:0> ap Purchase.last(3)
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
from (irb):21
It turns out I can't do much of anything:
irb(main):023:0> ap Purchase.find(28444)
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
from (irb):23
irb(main):024:0> ap Purchase.find(28444).gateway_response
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
from (irb):24
What's going on?
回答1:
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).
来源:https://stackoverflow.com/questions/50538446/why-am-i-getting-strong-parameter-errors-in-the-rails-console-in-rails-5