Rails 5:无法从参数中检索哈希值

Posted

技术标签:

【中文标题】Rails 5:无法从参数中检索哈希值【英文标题】:Rails 5: unable to retrieve hash values from parameter 【发布时间】:2016-04-29 05:14:43 【问题描述】:

我遇到了一个奇怪的问题。

undefined method `values' for #<ActionController::Parameters:0x007fb06f6b2728>

是我得到的错误,当我将变量分配给参数哈希并尝试获取它的值时。

attributes = params[:line_item][:line_item_attributes_attributes] || 
attributes.values

参数看起来像这样的哈希散列:

"0"=>"product_attribute_id"=>"4", "1"=>"product_attribute_id"=>"7"

现在,当我在控制台中执行此操作并将其分配给变量属性时,它可以完美地工作。所以我很难理解什么在这里不起作用 - 以及如何让它起作用。

【问题讨论】:

这确实很奇怪。 ActionController::Parameters 类的任何对象都应该响应 values。你的 ruby​​ 和 rails 版本是什么?你能加一个logger.warn attributes.inspect吗? 【参考方案1】:

我认为正在发生的事情如下:

在控制台中,您正在使用一个名为attributes 的简单哈希。作为散列,控制台中的attributes 参数有a valid instance method,称为values

在您的 rails 应用程序中,params 哈希不再是简单的哈希。它是ActionController::Parameters 类的一个实例。作为该类的一个实例,它没有名为values 的实例方法,但它确实有an instance method called to_hto_unsafe_h,这将实现您的目标。在您的参数上调用to_h 后,您可以调用values 方法。

【讨论】:

但是类ActionController::Parameters,是Hash的子类,而后者有一个方法values 更具体地说,在控制台中尝试params = ActionController::Parameters.new(line_item: ActionController::Parameters.new(line_item_attributes_attributes: ActionController::Parameters.new)); attributes = params[:line_item][:line_item_attributes_attributes] || ; puts attributes.class; attributes.values true...您也可以简单地运行ActionController::Parameters.method_defined? :values,您会发现 values 是一种有效的方法...现在我很难过 @tillmo 深入研究 Ruby,尽管您可以尝试使用您的 params 变量:params.kind_of? Hash #=&gt; true,然后尝试 params.instance_of? Hash #=&gt; false 所以 params 是一种哈希,但不是哈希的实例...为什么会这样? 查看 Rails 5,Parameters 不再从 Hash 继承(通过 HashWithIndifferentAccess),但他们确实添加了 :values 作为委托方法,所以它应该仍然有效......这是 Rails 5 @987654323 @ 与 Rails 4 code【参考方案2】:

看看this。很奇怪,因为ActionController::Parameters 是 Hash 的子类,您可以使用 params 哈希上的 to_h 方法将其 directly 转换为哈希。

但是 to_h 仅适用于列入白名单的参数,因此您可以执行以下操作:

permitted = params.require(:line_item).permit(: line_item_attributes_attributes)
attributes = permitted.to_h || 
attributes.values

但如果您不想加入白名单,则只需使用to_unsafe_h 方法。

更新

我对这个问题很好奇,所以我开始研究,现在你澄清了你正在使用 Rails 5,这就是这个问题的原因,正如@tillmo 在 Rails 4.x 等稳定版本中所说, ActionController::Parameters 是 Hash 的子类,所以它确实应该响应 values 方法,但是在 Rails 5 中 ActionController::Parameters 现在返回一个 Object 而不是一个 Hash

注意:这不会影响访问参数哈希中的键,例如params[:id]。您可以查看实现此更改的Pull Request。

要访问对象中的参数,您可以在参数中添加to_h

params.to_h

如果我们查看ActionController::Parameters 中的to_h 方法,我们可以看到它在将参数转换为哈希之前检查参数是否被允许。

# actionpack/lib/action_controller/metal/strong_parameters.rb
def to_h
  if permitted?
    @parameters.to_h
  else
    slice(*self.class.always_permitted_parameters).permit!.to_h
  end
end

例如:

def do_something_with_params
  params.slice(:param_1, :param_2)
end

哪个会返回:

 :param_1 => "a", :param_2 => "2" 

但现在这将返回一个 ActionController::Parameters 对象。

在此调用 to_h 将返回一个空哈希,因为 param_1 和 param_2 是不允许的。

要从ActionController::Parameters 访问参数,您需要先允许这些参数,然后在对象上调用to_h

def do_something_with_params
  params.permit([:param_1, :param_2]).to_h
end

上面将返回一个带有您刚刚允许的参数的哈希,但如果您不想允许这些参数并想跳过该步骤,还有另一种使用to_unsafe_hash 方法的方法:

def do_something_with_params
  params.to_unsafe_h.slice(:param_1, :param_2)
end

有一种方法总是允许来自 application.rb 的配置中的参数,如果你想总是允许某些参数,你可以设置一个配置选项。注意:这将返回带有字符串键的哈希,而不是符号键。

#controller and action are parameters that are always permitter by default, but you need to add it in this config.
config.always_permitted_parameters = %w( controller action param_1 param_2)

现在您可以访问以下参数:

def do_something_with_params
  params.slice("param_1", "param_2").to_h
end

请注意,现在键是字符串而不是符号。

希望这可以帮助您了解问题的根源。

来源:eileen.codes

【讨论】:

但是这个类,即ActionController::Parameters,是Hash的子类,而后者有一个方法values 实际上并非如此,这就是该类中有 to_h 方法的原因 试试params = ActionController::Parameters.new; params.values,看看这里不需要to_h 嗯,它开始变得有意义了......大声笑可能与 Rails 版本有关? 我正在运行 rails 5.0 beta1,尝试在参数上添加 .to_h,但它给了我一个空哈希【参考方案3】:

忠告:如果您使用来自 sorted gem 的 link_to_sorted,它会破坏 Rails 5 中的视图。

【讨论】:

【参考方案4】:

从 Rails 5 开始,参数属于 'ActionController::Parameters' 类

如果你做 params.to_h 你会得到以下错误。

*** ActionController::UnfilteredParameters Exception: unable to convert 
unpermitted parameters to hash

您可以执行以下操作以允许所有参数并以哈希格式获取:

parameters = params.permit(params.keys).to_h

“但要小心使用它!您允许所有可能包含可能损害您的代码的未知参数的参数。”

【讨论】:

以上是关于Rails 5:无法从参数中检索哈希值的主要内容,如果未能解决你的问题,请参考以下文章

使用 RSpec 测试 Rails 辅助方法时如何在参数哈希中设置值?

将 Rails 参数哈希传递给命名路由的更有效方法

哪个哈希码哈希映射实现用于值检索

Rails 强参数 - 允许在数组中进行深度嵌套哈希

ruby 符号作为键,但无法从哈希中获取值

sh 如何在Git中检索当前提交的哈希值?