我有一个在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
而不是预期的行为。我认为这是因为键现在是字符串而不是符号。
我知道我可以构建一个带符号的新哈希作为键,但这似乎比它的价值更麻烦。想法?建议?
答案 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
方法,该方法根据需要将数据结构化以传递给方法像这样。