Rails: 在不使用它返回的对象时调用 ActionController::Parameters#permit() 有什么用?
Rails: What does calling ActionController::Parameters#permit() achieve when not using the object returned by it?
I understand 调用 params.permit(:foo)
会创建一个新的 ActionController::Parameters
实例,并将 :foo
列入白名单,以便您可以使用它实例化模型。但为什么 Discourse CMS 中的以下代码调用它而不使用其 return 值?
discourse/app/controllers/drafts_controller.rb
: Github
class DraftsController < ApplicationController
# [...]
def index
# [...]
params.permit(:offset)
params.permit(:limit)
# [...]
opts = {
# [...]
offset: params[:offset],
limit: params[:limit]
}
stream = Draft.stream(opts)
这看起来确实令人困惑,我同意。
从 #permit
and the documentation of ActionController::Params
的实现来看,这可能会根据配置 action_on_unpermitted_parameters
的不同而有所不同,它接受 :log
和 :raise
作为值并且是 nil
默认。
当action_on_unpermitted_parameters = nil
:
调用 params.permit(:foo)
将 return 一个新的 ActionController::Parameters
实例标记为仅使用该密钥允许。
如果您没有使用 return 值,则此调用没有任何意义,因为没有副作用。接收者没有变异。
当action_on_unpermitted_parameters = :log
:
这与上面的行为相同,但具有记录所有不允许的键的副作用:
irb> ActionController::Parameters.action_on_unpermitted_parameters = :log
=> :log
irb> params = ActionController::Parameters.new(username: 'john', offset: 5, bogus: 'foo')
=> <ActionController::Parameters {"username"=>"john", "offset"=>5, "bogus"=>"foo"} permitted: false>
irb> params.require(:username)
=> "john"
irb> params.permit(:offset)
Unpermitted parameters: :username, :bogus
=> <ActionController::Parameters {"offset"=>5} permitted: true>
irb> params.permit(:limit)
Unpermitted parameters: :username, :offset, :bogus
=> <ActionController::Parameters {} permitted: true>
如您所见,对于每个 permit
调用,您会得到不同的日志。因此,只有当该控制器中的代码包含所有允许的(和必需的)参数时,这才有意义:
irb> params.permit(:username, :offset, :limit)
Unpermitted parameter: :bogus
=> <ActionController::Parameters {"username"=>"john", "offset"=>5} permitted: true>
当action_on_unpermitted_parameters = :raise
:
这里的效果是当参数包含不允许的键时引发。类似于 :log
,这也只有在指定了所有允许(和必需)的键时才有意义:
irb> ActionController::Parameters.action_on_unpermitted_parameters = :raise
=> :raise
irb> params = ActionController::Parameters.new(username: 'john', offset: 5, bogus: 'foo')
=> <ActionController::Parameters {"username"=>"john", "offset"=>5, "bogus"=>"foo"} permitted: false>
irb> params.require(:username)
=> "john"
irb> params.permit(:offset)
Traceback (most recent call last):
1: from (irb):19
ActionController::UnpermittedParameters (found unpermitted parameters: :username, :bogus)
irb> params.permit(:limit)
Traceback (most recent call last):
2: from (irb):20
1: from (irb):20:in `rescue in irb_binding'
ActionController::UnpermittedParameters (found unpermitted parameters: :username, :offset, :bogus)
对比包括所有键:
irb> params.permit(:username, :offset, :limit)
Traceback (most recent call last):
2: from (irb):21
1: from (irb):21:in `rescue in irb_binding'
ActionController::UnpermittedParameters (found unpermitted parameter: :bogus)
话虽如此,我在 Discourse 的代码库中找不到任何 action_on_unpermitted_parameters
的出现。因此,该值为 nil
,因此我得出结论,该控制器操作中的 #permit
在功能方面没有影响。
它可以作为一个惯例作为文档,其中首先列出所有必需参数,然后列出所有可选参数。
深入挖掘,这些 #permit
调用是在此 commit 中引入的,当时它仍然是一个单独的 gem 调用 strong_parameters. #permit
在 gem 中的行为与今天相同。这让我认为该提交的作者误解了 strong_parameters.
的 API
I understand 调用 params.permit(:foo)
会创建一个新的 ActionController::Parameters
实例,并将 :foo
列入白名单,以便您可以使用它实例化模型。但为什么 Discourse CMS 中的以下代码调用它而不使用其 return 值?
discourse/app/controllers/drafts_controller.rb
: Github
class DraftsController < ApplicationController
# [...]
def index
# [...]
params.permit(:offset)
params.permit(:limit)
# [...]
opts = {
# [...]
offset: params[:offset],
limit: params[:limit]
}
stream = Draft.stream(opts)
这看起来确实令人困惑,我同意。
从 #permit
and the documentation of ActionController::Params
的实现来看,这可能会根据配置 action_on_unpermitted_parameters
的不同而有所不同,它接受 :log
和 :raise
作为值并且是 nil
默认。
当action_on_unpermitted_parameters = nil
:
调用 params.permit(:foo)
将 return 一个新的 ActionController::Parameters
实例标记为仅使用该密钥允许。
如果您没有使用 return 值,则此调用没有任何意义,因为没有副作用。接收者没有变异。
当action_on_unpermitted_parameters = :log
:
这与上面的行为相同,但具有记录所有不允许的键的副作用:
irb> ActionController::Parameters.action_on_unpermitted_parameters = :log
=> :log
irb> params = ActionController::Parameters.new(username: 'john', offset: 5, bogus: 'foo')
=> <ActionController::Parameters {"username"=>"john", "offset"=>5, "bogus"=>"foo"} permitted: false>
irb> params.require(:username)
=> "john"
irb> params.permit(:offset)
Unpermitted parameters: :username, :bogus
=> <ActionController::Parameters {"offset"=>5} permitted: true>
irb> params.permit(:limit)
Unpermitted parameters: :username, :offset, :bogus
=> <ActionController::Parameters {} permitted: true>
如您所见,对于每个 permit
调用,您会得到不同的日志。因此,只有当该控制器中的代码包含所有允许的(和必需的)参数时,这才有意义:
irb> params.permit(:username, :offset, :limit)
Unpermitted parameter: :bogus
=> <ActionController::Parameters {"username"=>"john", "offset"=>5} permitted: true>
当action_on_unpermitted_parameters = :raise
:
这里的效果是当参数包含不允许的键时引发。类似于 :log
,这也只有在指定了所有允许(和必需)的键时才有意义:
irb> ActionController::Parameters.action_on_unpermitted_parameters = :raise
=> :raise
irb> params = ActionController::Parameters.new(username: 'john', offset: 5, bogus: 'foo')
=> <ActionController::Parameters {"username"=>"john", "offset"=>5, "bogus"=>"foo"} permitted: false>
irb> params.require(:username)
=> "john"
irb> params.permit(:offset)
Traceback (most recent call last):
1: from (irb):19
ActionController::UnpermittedParameters (found unpermitted parameters: :username, :bogus)
irb> params.permit(:limit)
Traceback (most recent call last):
2: from (irb):20
1: from (irb):20:in `rescue in irb_binding'
ActionController::UnpermittedParameters (found unpermitted parameters: :username, :offset, :bogus)
对比包括所有键:
irb> params.permit(:username, :offset, :limit)
Traceback (most recent call last):
2: from (irb):21
1: from (irb):21:in `rescue in irb_binding'
ActionController::UnpermittedParameters (found unpermitted parameter: :bogus)
话虽如此,我在 Discourse 的代码库中找不到任何 action_on_unpermitted_parameters
的出现。因此,该值为 nil
,因此我得出结论,该控制器操作中的 #permit
在功能方面没有影响。
它可以作为一个惯例作为文档,其中首先列出所有必需参数,然后列出所有可选参数。
深入挖掘,这些 #permit
调用是在此 commit 中引入的,当时它仍然是一个单独的 gem 调用 strong_parameters. #permit
在 gem 中的行为与今天相同。这让我认为该提交的作者误解了 strong_parameters.