为什么我在 rails 5 的 Rails 控制台中出现严重的参数错误?
Why am I getting strong parameter errors in the Rails Console in rails 5?
我想在我的控制台中调用它(ap
是很棒的打印 gem):
ap Purchase.last(10)
但是我得到这个错误:
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
它是这样工作的:
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
}
没有像这样的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 [["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 |
但不带参数并且ap
irb(main):021:0> ap Purchase.last(3)
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
from (irb):21
原来我什么都做不了:
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
怎么回事?
发生了什么以及为什么
ActionController::Parameters
(这是 params
在控制器中的作用)用于继承自 HashWithIndifferentAccess
,后者继承自 Hash
。所以 ActionController::Parameters < Hash
曾经是真实的,就像这样:
params.require(:x).permit(some_hash: %i[key1 key2]).is_a? Hash
如果您从 params
中挖掘 Hash
:
some_hash = params.require(:x).permit(some_hash: ...)
并在模型中序列化:
class M < ApplicationRecord # Or ActiveRecord::Base in the past
serialize :h, Hash
end
#...
m.h = some_hash
你最终可能会在你的数据库中得到这样的 YAML:
--- !ruby/object:ActionController::Parameters
...
而不是预期的纯 YAMLized 哈希。
但是后来 Rails5 出现了 ActionController::Parameters
no longer inherits from Hash
:
- Make
ActionController::Parameters
no longer inherits from HashWithIndifferentAccess
.
并且在 ActionController::Parameters
上调用 to_h
或 to_hash
现在会引发异常。
如果您升级代码并尝试加载其中包含序列化数据的模型:
serialize :h, Hash
然后模型将从 h
加载文本,解析 YAML 以获取 ActionController::Parameters
实例,并对其调用 to_h
以确保它具有哈希,并且你得到一个例外。
怎么办
您需要做几件事:
- 修复您的控制器以确保它们从
params
. 中获得真正的哈希值
- 修复您的数据,使您拥有序列化哈希而不是
ActionController::Parameters
个实例。
修复控制器很简单,只需对尚未真正散列的参数调用 to_unsafe_h
。
修复数据更难看。我可能会使用低级数据库接口(即任何地方都没有 ActiveRecord)浏览表格,从每一行中读取 YAML,YAML.load
它,通过调用 to_unsafe_h
将其转换为散列,然后写回 the_real_hash.to_yaml
文本。您可以在 WHERE 子句中使用 like '--- !ruby/object:ActionController::Parameters%'
过滤器来仅处理损坏的行。
我还强烈建议您在那里时停止使用 serialize
。 serialize
有点乱七八糟,在数据库中没有使用 YAML 的明智方法;现在 PostgreSQL 和 MySQL 都有原生的 JSON 支持(但我不确定 ActiveRecord 对 MySQL 的 JSON 的支持有多好)。
我想在我的控制台中调用它(ap
是很棒的打印 gem):
ap Purchase.last(10)
但是我得到这个错误:
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
它是这样工作的:
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
}
没有像这样的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 [["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 |
但不带参数并且ap
irb(main):021:0> ap Purchase.last(3)
ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
from (irb):21
原来我什么都做不了:
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
怎么回事?
发生了什么以及为什么
ActionController::Parameters
(这是 params
在控制器中的作用)用于继承自 HashWithIndifferentAccess
,后者继承自 Hash
。所以 ActionController::Parameters < Hash
曾经是真实的,就像这样:
params.require(:x).permit(some_hash: %i[key1 key2]).is_a? Hash
如果您从 params
中挖掘 Hash
:
some_hash = params.require(:x).permit(some_hash: ...)
并在模型中序列化:
class M < ApplicationRecord # Or ActiveRecord::Base in the past
serialize :h, Hash
end
#...
m.h = some_hash
你最终可能会在你的数据库中得到这样的 YAML:
--- !ruby/object:ActionController::Parameters
...
而不是预期的纯 YAMLized 哈希。
但是后来 Rails5 出现了 ActionController::Parameters
no longer inherits from Hash
:
- Make
ActionController::Parameters
no longer inherits fromHashWithIndifferentAccess
.
并且在 ActionController::Parameters
上调用 to_h
或 to_hash
现在会引发异常。
如果您升级代码并尝试加载其中包含序列化数据的模型:
serialize :h, Hash
然后模型将从 h
加载文本,解析 YAML 以获取 ActionController::Parameters
实例,并对其调用 to_h
以确保它具有哈希,并且你得到一个例外。
怎么办
您需要做几件事:
- 修复您的控制器以确保它们从
params
. 中获得真正的哈希值
- 修复您的数据,使您拥有序列化哈希而不是
ActionController::Parameters
个实例。
修复控制器很简单,只需对尚未真正散列的参数调用 to_unsafe_h
。
修复数据更难看。我可能会使用低级数据库接口(即任何地方都没有 ActiveRecord)浏览表格,从每一行中读取 YAML,YAML.load
它,通过调用 to_unsafe_h
将其转换为散列,然后写回 the_real_hash.to_yaml
文本。您可以在 WHERE 子句中使用 like '--- !ruby/object:ActionController::Parameters%'
过滤器来仅处理损坏的行。
我还强烈建议您在那里时停止使用 serialize
。 serialize
有点乱七八糟,在数据库中没有使用 YAML 的明智方法;现在 PostgreSQL 和 MySQL 都有原生的 JSON 支持(但我不确定 ActiveRecord 对 MySQL 的 JSON 的支持有多好)。