如何解决"Method to_hash is deprecated and will be removed in Rails 5.1"的弃用警告?

42

我试图升级到Rails 5,但遇到以下弃用警告:

 

DEPRECATION WARNING: 方法to_hash已过时,并将在Rails 5.1中删除,因为不再继承自hash。使用此弃用的行为会暴露潜在的安全问题。如果你继续使用此方法,则可能会在应用程序中创建一个可被利用的安全漏洞。相反,请考虑使用这些已记录的未弃用的方法之一:http://api.rubyonrails.org/v5.0.0/classes/ActionController/Parameters.html(位于/Data/Projects/portal/trunk/app/helpers/application_helper.rb的column_header中调用)

警告出现的代码行如下:

    link_to(name,
            {
              action: action_name,
              params: params.merge({ order: key, page: nil })
            },
            {
              title: "Sort by this field",
            }) +

正如您所看到的,我没有调用to_hash。可能是Rails,也可能是其他一些宝石库。我无法确定,因为他们不认为提供堆栈跟踪值得一提。(专业技巧 - 通常值得提供堆栈跟踪!)

无论如何,我按照链接,打算找到替代方案,但是合并的merge方法似乎未被弃用,但也许他们只是忘记记录弃用状态,所以我无法确定。

那我该怎么清理它呢?


params.merge 还是 link_to 调用了 to_hash - mu is too short
我至少看了一下params.merge,它没有问题。也许是link_to有问题...如果是这样的话,我可能会认为这是Rails的错?我真的不知道。(这正是为什么堆栈跟踪很有用的原因-我宁愿不必挖掘库源代码来找出谁犯了错误) - Hakanai
你确定应该通过名为 params 的参数来指定 url_for 的参数,而不是直接在顶层传递参数,例如:link_to(name, {action: action_name, order: key, page: nil}.merge(params) - Mladen Jablanović
如果你真的需要传递 {params: params},请尝试使用 {params: params.to_h} - Mladen Jablanović
那我会调用他们告诉我的不要调用的方法。我想我可以使用to_unsafe_h... - Hakanai
显示剩余3条评论
1个回答

76

使用 .to_h

你可以调用.to_h方法来获取一个安全的哈希表,根据Rails PR上的评论

现在有三种方法可以将参数转换为哈希表。

  • .to_h 表示 "如果我没有调用.permit,假定什么都不允许。"
  • .to_unsafe_h 表示 "如果我没有调用.permit,假定一切都允许。"
  • .to_hash 现在存在歧义。Rails将它视为.to_unsafe_h,但会打印警告,因为你没有明确说明你需要上述两个选项中的哪一个。

首先,让我们看看如果您没有调用.permit会发生什么。在Rails 5.0控制台中:

> params = ActionController::Parameters.new({yes: "y", no: "n"})

> params.to_h
{} # empty hash because nothing has been permitted

> params.to_unsafe_h
{"yes"=>"y", "no"=>"n"} # raw values with no warning; you asked for it

> params.to_hash
# (puts deprecation warning - if you want unsafe values, say so)
{"yes"=>"y", "no"=>"n"} # returns raw values

然而,如果您首先调用.permit,就没有获取非允许值的方法了。

> params = ActionController::Parameters.new({yes: "y", no: "n"})

> params = params.permit(:yes)
# (puts warning about unpermitted parameter :no)

> params.to_h
{"yes"=>"y"} # permitted values only

> params.to_unsafe_h
{"yes"=>"y"} # permitted values only

> params.to_hash
# (puts deprecation warning, but still safe)
{"yes"=>"y"} # permitted values only

所以:

  1. 始终使用.permit来列出您期望的值
  2. 使用.to_h确保如果您忘记了第一步,什么都不会被传递
  3. 如果你真的想要原始值,不要调用.permit,改为调用.to_unsafe_hash
  4. 不要调用.to_hash,因为这现在是有歧义的

我认为这里我必须使用to_unsafe_hash - 正如你所说,使用to_h只会返回被允许的内容,但是在库代码中,我不知道哪些参数是允许的。因此,任何我使用permit的操作都需要迭代所有键,这似乎和to_unsafe_hash一样糟糕。而且,我要做的就是生成一个最终会变成params的URL。很遗憾Parameters本身不能用于url_for,但没关系。 - Hakanai
嗯。如果你在库代码中,那么参数是从哪里获取的?如果一个应用程序调用你的库,他们应该在交给你参数之前调用.permit,对吧?你可以通过params.permitted?来检查这一点。我会对使用任意参数构建URL感到紧张,特别是在库代码中,因为你不知道它们来自哪里。 - Nathan Long
参数来自控制器,但所讨论的哈希表用于过滤和排序。我想我不应该复制代码以允许所有筛选器的完整列表。我必须想出一些编程方式来动态获取列表。 :/ - Hakanai
我不明白为什么这个答案被投票赞成,因为尽管它提供了一个很好的解释,但它根本没有回答问题(OP想知道 - 就像我一样 - 是谁/在哪里首先调用.to_hash)。 - sandre89
2
@sandre89 这个问题说:“我收到了以下弃用警告...(详细信息)那么我应该怎么做才能清除它?” - Nathan Long
这是对这个问题非常有帮助、清晰明了和简洁的回答。愿上帝保佑你。 - a2f0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接