查看此代码:
params[:id]
Params被认为是一个方法。如果我错了,请纠正我。但这就像从散列中读取一样。所以,我现在很困惑。
如果params是一个方法:显示的代码示例如何工作?
你是正确的,params
是一个方法,但在这里params
方法返回ActionController::Parameters
的实例,我们调用哈希访问器方法#[]
。
这是ruby中对返回对象调用方法的常见模式。让我们看一个简单的例子:
def params
{
id: 101,
key: 'value',
foo: 'bar'
}
end
params[:id] # => 101
params[:foo] # => 'bar'
在示例中可以看到,方法params
返回一个哈希对象,我们在返回的对象上调用哈希访问器方法#[]
。
参考railsparams
方法:https://github.com/rails/rails/blob/5e1a039a1dd63ab70300a1340226eab690444cea/actionpack/lib/action_controller/metal/strong_parameters.rb#L1215-L1225
def params
@_params ||= begin
context = {
controller: self.class.name,
action: action_name,
request: request,
params: request.filtered_parameters
}
Parameters.new(request.parameters, context)
end
end
ruby初学者注意:在ruby中,我们可以调用不带括号的方法。因此,上面的调用相当于params()[:id]
。
这些被称为方括号访问器,您可以通过实现[]
和[]=
方法将它们添加到任何对象中。
class Store
def initialize(**kwargs)
kwargs.each { |k,v| instance_variable_set("@#{k}", v) }
end
def [](key)
instance_variable_get("@#{key}")
end
def []=(key, value)
instance_variable_set("@#{key}", value)
end
end
store = Store.new(foo: 1, bar: 2, baz: 3)
store[:foo] # 1
store[:foo] = 100
store[:foo] # 100
同样,当你调用params[:id]
时,params
方法将首先被调用,所以你在ActionController::Parameters的实例上调用[]
,就像下面这个简单的例子:
def foo
Store.new(bar: 1)
end
foo[:bar] # 1
由于父类是可选的,它相当于调用params()[:id]
。
在控制器的上下文中,params
确实是一个方法。假设我们有一个OrganizationsController
,它在restful端点中公开#index
操作。我将使用pry gem添加一个断点,以便我们可以更好地理解params
是什么:
class OrganizationsController < ApplicationController
def index
binding.pry # Runtime will stop here
render json: Organization.all
end
end
让我们访问以下URL:
http://localhost: 3000/organizations.json吗?foo = bar
我们实际上可以通过显式调用()
来验证params
是一个方法:
> params()
=> #<ActionController::Parameters {"foo"=>"bar", "controller"=>"organizations", "action"=>"index", "format"=>"json"} permitted: false>
或者询问Ruby该方法在哪里定义:
> method(:params).source_location
=> ["/home/myuser/.rvm/gems/ruby-3.0.2@myproject/gems/actionpack-6.1.4.1/lib/action_controller/metal/strong_parameters.rb", 1186]
调用params
返回的对象不是Hash
,而是ActionController::Parameters
:
> params.class
=> ActionController::Parameters
然而,我们可以调用:[]
方法,因为它实际上是在ActionController::Parameters
类中定义的(见代码)
这使得它看起来像是一个Hash
,但实际上它不是。例如,我们不能调用Hash
方法params
反转,因为它没有定义:
> params.invert
NoMethodError: undefined method `invert' for #<ActionController::Parameters {"foo"=>"bar", "controller"=>"organizations", "action"=>"index", "format"=>"json"} permitted: false>