【问题标题】:Why am I getting strong parameter errors in the Rails Console in rails 5?为什么我在 rails 5 的 Rails 控制台中出现严重的参数错误?
【发布时间】:2018-05-26 01:00:34
【问题描述】:

我想在我的控制台中调用它(ap 是很棒的打印宝石):

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 $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         |

但没有参数和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

发生了什么事?

【问题讨论】:

  • 数据库中的gateway_response 是什么?序列化params 或许?
  • 我问的原因是因为ActionController::Parameters 曾经继承自Hash,所以你可以serialize :stuff, Hash,将params 放入stuff,最后得到一团YAML在标记为ActionController::Parameters 实例的数据库中。但是ActionController::Parameters 不再继承自Hash 并且它的to_h 方法引发了异常。结果是,如果您没有非常小心,更改 Rails 版本可能会使您的数据库中充斥着损坏的数据。
  • @muistooshort 就是这样。我并不是所有的购买都有网关响应,因为购买可以通过不同的方式进行。一些网关响应来自 Authorize.net(旧的),一些来自 Stripe,一些来自 Paypal。根据我的代码,这些序列化响应具有不同的类,正如您所说,看起来来自 Paypal 的响应被序列化为 ActionController::Parameters。我最近将我的应用程序从 4.2 升级到了 5.2,看起来我需要清理我的数据库。随时发表您的评论作为答案,我会接受。

标签: ruby-on-rails rails-activerecord strong-parameters awesomeprint


【解决方案1】:

发生了什么以及为什么

ActionController::Parameters(这是 params 在控制器中使用的)曾经继承自 HashWithIndifferentAccess,后者继承自 Hash。所以ActionController::Parameters &lt; 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
...

而不是预期的纯 YAML 化哈希。

但随后 Rails5 出现了,ActionController::Parameters no longer inherits from Hash:

  • 使ActionController::Parameters 不再继承自HashWithIndifferentAccess

现在在 ActionController::Parameters 上调用 to_hto_hash 会引发异常。

如果您升级代码并尝试加载其中包含序列化数据的模型:

serialize :h, Hash

然后模型将从 h 加载文本,解析 YAML 以获取 ActionController::Parameters 实例,并在其上调用 to_h 以确保它具有哈希,并且您会得到一个异常。

怎么办

你需要做几件事:

  1. 修复您的控制器以确保它们从 params 中获取真正的哈希值。
  2. 修复您的数据,以便序列化哈希而不是 ActionController::Parameters 实例。

修复控制器很简单,只需对尚未真正散列的参数调用 to_unsafe_h

修复数据更难看。我可能会使用低级数据库接口(即任何地方都没有 ActiveRecord)浏览表,从每一行读取 YAML,YAML.load 它,通过调用 to_unsafe_h 将其转换为哈希,然后写入返回the_real_hash.to_yaml 文字。您可以在 WHERE 子句中使用 like '--- !ruby/object:ActionController::Parameters%' 过滤器来仅处理损坏的行。

我还强烈建议您停止使用serializeserialize 有点杂乱无章,在数据库中使用 YAML 没有理智的方法;现在也很少需要它,因为 PostgreSQL 和 MySQL 都具有原生 JSON 支持(但我不确定 ActiveRecord 对 MySQL 的 JSON 的支持程度)。

【讨论】:

    猜你喜欢
    • 2017-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多