pix*_*rth 0 ruby-on-rails strong-parameters awesomeprint rails-activerecord
我想在我的控制台中调用它(ap是很棒的打印宝石):
ap Purchase.last(10)
Run Code Online (Sandbox Code Playgroud)
但我收到此错误:
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
Run Code Online (Sandbox Code Playgroud)
它的工作原理如下:
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
}
Run Code Online (Sandbox Code Playgroud)
没有ap这样的:
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 |
Run Code Online (Sandbox Code Playgroud)
但不是有争论和ap
irb(main):021:0> ap Purchase.last(3)
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
from (irb):21
Run Code Online (Sandbox Code Playgroud)
事实证明我无能为力:
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
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?
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
Run Code Online (Sandbox Code Playgroud)
If you were digging a Hash out of params:
some_hash = params.require(:x).permit(some_hash: ...)
Run Code Online (Sandbox Code Playgroud)
and serializing that in a model:
class M < ApplicationRecord # Or ActiveRecord::Base in the past
serialize :h, Hash
end
#...
m.h = some_hash
Run Code Online (Sandbox Code Playgroud)
you could end up with some YAML like this in your database:
--- !ruby/object:ActionController::Parameters
...
Run Code Online (Sandbox Code Playgroud)
rather than the expected plain YAMLized hash.
But then Rails5 comes along and ActionController::Parameters no longer inherits from Hash:
- Make
ActionController::Parametersno 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
Run Code Online (Sandbox Code Playgroud)
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.
There are a couple things you need to do:
params.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).