我有一个稍微定制的 Devise 与 Rails 5 应用程序的集成。我继承
Devise::RegistrationsController
并为 create
资源实现我自己的 User
操作,而不是调用 super
。
在开发过程中的所有时间,以及在生产过程中的大部分时间,
params
从形式上来看是这样的:
{
"utf8"=>"✓",
"authenticity_token"=>"***",
"user"=> {
"email"=>"[email protected]",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"
},
"commit"=>"Create account"
}
但少数情况下,仅在生产中,
params
看起来像这样:
{
"utf8"=>"✓",
"authenticity_token"=>"***",
"user[email]"=>"[email protected]",
"user[password]"=>"[FILTERED]",
"user[password_confirmation]"=>"[FILTERED]",
"commit"=>"Create account",
"registration"=> {
"user[email]"=>"[email protected]",
"user[password]"=>"[FILTERED]",
"user[password_confirmation]"=>"[FILTERED]",
"commit"=>"Create account"
}
}
我不知道为什么会出现第二种形式的参数。我的假设是,在某些情况下,Devise 以不同的方式处理参数。我能想到检查的唯一情况是在验证问题后重新提交,每次我尝试此操作时,参数仍然以第一种形式出现(在开发和生产中)。
create
操作是在假设 params[:user]
具有用户属性哈希的情况下编写的,而第二种形式的情况并非如此。我可以处理这些参数的两种形式,但我想了解为什么会发生这种情况,并且我不希望使用随机不同的参数调用此操作。
如果相关,提交表单(省略样式类):
<%= form_for(@user, as: :user, url: registration_path(:user)) do |f| %>
<div class="row">
<%= f.label :email %>
<%= f.email_field :email, autofocus: true %>
</div>
<div class="row">
<%= f.label :password %>
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="row">
<%= f.label :password_confirmation, 'Password confirmation' %>
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="row">
<div>
<%= f.submit "Create account" %>
</div>
</div>
<% end %>
ActionController::ParamsWrapper
启动时就会发生这种情况。
启用后,参数包装器会使用当前控制器的名称(如果尚未嵌套在该名称下)来包装传入参数。
在您的示例中,您将嵌套在
user
下的参数发送到名为 RegistrationsController
的控制器。因此,ParamsWrapper 再次用 registration
包裹它们。如果您将它们发送到 UsersController
,则它们不会发生更改,因为它们已经嵌套在 user
下。
恕我直言,这是 Ruby on Rails 最无用且最容易出错的魔法行为之一。我通常会立即禁用它,因为它经常会导致问题。例如,当前端不做任何嵌套,仅依赖此功能,但后端需要重构并引入命名空间或重命名控制器时。