繁体   English   中英

Ruby 2 关键字 Arguments 和 ActionController::Parameters

[英]Ruby 2 Keyword Arguments and ActionController::Parameters

我有一个运行在 ruby 2.1 上的 Rails 4 应用程序。 我有一个User model 看起来像

class User < ActiveModel::Base
  def self.search(query: false, active: true, **extra)
    # ...
  end
end

正如您在搜索方法中看到的那样,我正在尝试使用 ruby 2 的新关键字 arguments 功能。

问题是,当我从我的 controller 中调用此代码时,所有值都被转储到query中。

参数

{"action"=>"search", "controller"=>"users", query: "foobar" }

请注意,这是一个 ActionController::Parameters object 而不是它看起来的 hash

用户控制器

def search
  @users = User.search(params)
end

我觉得这是因为 params 是一个ActionController::Parameters object 而不是 hash。但是,即使在传入参数时调用to_h将所有内容转储到query中,而不是预期的行为。 我认为这是因为键现在是字符串而不是符号。

我知道我可以构建一个新的 hash w/ 符号作为键,但这似乎比它的价值更麻烦。 想法? 建议?

关键字参数必须作为散列传递符号,而不是字符串:

class Something
  def initialize(one: nil)
  end
end

irb(main):019:0> Something.new("one" => 1)
ArgumentError: wrong number of arguments (1 for 0)

ActionController::Parameters继承自ActiveSupport::HashWithIndifferentAccess ,默认为字符串键:

a = HashWithIndifferentAccess.new(one: 1)
=> {"one"=>1}

要使其成为符号,您可以调用symbolize_keys方法。 在您的情况下: User.search(params.symbolize_keys)

我同意Morgoth,但是,对于rails~5,你会得到一个弃用警告,因为ActionController :: Parameters不再继承哈希。 所以你可以这样做:

params.to_unsafe_hash.symbolize_keys

或者如果你有嵌套参数,就像构建api端点时经常这样:

params.to_unsafe_hash.deep_symbolize_keys

您可以向ApplicationController添加一个看起来像这样的方法:

def unsafe_keyworded_params
  @_unsafe_keyworded_params ||= params.to_unsafe_hash.deep_symbolized_keys
end

你很可能确实需要它们作为符号。 尝试这个:

def search
  @users = User.search(params.inject({}){|para,(k,v)| para[k.to_sym] = v; para}
end

我知道这不是理想的解决方案,但它只是一个班轮。

在这个特定的例子中,我认为你最好通过params对象并将其视为处理它而不是试图巧妙地使用Ruby 2中的新功能。

首先,阅读这一点可以更清楚地了解变量的来源以及为什么它们可能会丢失/不正确/无论如何:

def search(params)
  raise ArgumentError, 'Required arguments are missing' unless params[:query].present?

  # ... do stuff ...
end

您尝试做的事情(在我看来)只会在尝试调试问题时解决问题并混淆:

def self.search(query: false, active: true, **extra)
  # ...
end

# Method explicitly asks for particular arguments, but then you call it like this:
User.search(params)

就个人而言,我认为代码有点臭。

但是...除了个人意见之外,我将如何修复它将是修补ActionController :: Parameters类并添加一个#to_h方法,该方法根据需要将数据结构化以传递给这样的方法。

使用to_unsafe_hash是不安全的,因为它包含不允许的参数。 (参见ActionController::Parameters#permit )更好的方法是使用to_hash

params.to_hash.symbolize_keys

或者如果你有嵌套的参数:

params.to_hash.deep_symbolize_keys

参考: https://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-to_hash

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM