Ruby 2关键字参数和ActionController ::参数

时间:2014-01-27 23:50:34

标签: ruby-on-rails ruby ruby-on-rails-4

我有一个在ruby 2.1上运行的rails 4应用程序。我有一个类似

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

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

问题是,当我在控制器中调用此代码时,所有值都会被转储到query

PARAMS

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

请注意,这是一个ActionController :: Parameters对象,而不是它看起来的哈希

UsersController

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

我觉得这是因为params是ActionController::Parameters对象而不是哈希。但是,在传递它时,甚至在params上调用to_h会将所有内容转储到query而不是预期的行为。我认为这是因为键现在是字符串而不是符号。

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

4 个答案:

答案 0 :(得分:8)

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

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)

答案 1 :(得分:4)

我同意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

答案 2 :(得分:0)

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

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

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

答案 3 :(得分:0)

在这个特定的例子中,我认为你最好不要传递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方法,该方法根据需要将数据结构化以传递给方法像这样。