为什么 Devise 使用自定义路由创建不正确的丢失密码 POST 路径
Why does Devise creates incorrect lost password POST path with custom route
我有一个带有普通用户模型的简单 Devise 安装。我确认默认路由一切正常(注册、丢失密码等),然后开始像这样自定义:
devise_for :users, :skip => [:sessions, :registrations, :passwords]
as :user do
get 'signin' => 'devise/sessions#new', :as => :new_user_session
post 'signin' => 'devise/sessions#create', :as => :user_session
delete 'signout' => 'devise/sessions#destroy', :as => :destroy_user_session
get 'register/cancel' => 'devise/registrations#cancel', :as => :cancel_user_registration
post 'register' => 'devise/registrations#create', :as => :user_registration
get 'register' => 'devise/registrations#new', :as => :new_user_registration
get 'account' => 'devise/registrations#edit', :as => :edit_user_registration
patch 'account' => 'devise/registrations#update'
put 'account' => 'devise/registrations#update'
delete 'account' => 'devise/registrations#destroy'
post 'password' => 'devise/passwords#create', :as => :user_password
get 'password/forgot' => 'devise/passwords#new', :as => :new_user_password
get 'password/reset' => 'devise/passwords#edit', :as => :edit_user_password
patch 'password' => 'devise/passwords#update'
put 'password' => 'devise/passwords#update'
end
然而,忘记密码页面会创建一个 POST 路径,如下所示:
<form class="new_user" id="new_user" action="/password.user" accept-charset="UTF-8" method="post">
...
</form>
从相应的观点来看:
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
使用默认的 Devise 路由,url 正确显示为 /users/password
,但使用我的自定义路由,我得到 /password.user
。好像只有这一条路。
我知道简单的解决方法是将 password_path(resource_name)
更改为 password_path
,但我想首先了解为什么会中断。
在深入研究 Devise 的源代码并进行一些试验之后,我想我已经找到了发生这种情况的原因。如果您查看 devise_for
为模型 :user
生成的路由,密码路由有一个前缀 user_password
。路由方法是 user_password_path
。那么 password_path
实际上是如何工作的呢?
new.html.erb
中调用的password_path
方法实际上并不是devise_for :user
生成的方法。它是一个以模型名称作为参数的辅助方法。例如,当传递 :user
时,它将如下所示:
password_path(:user) => user_password_path
此方法然后调用 user_password_path
,这是正确的方法。更多信息 here.
在你的例子中,你正在创建一个前缀为 user_password
的路由,但你也有这些路由:
patch 'password' => 'devise/passwords#update'
put 'password' => 'devise/passwords#update'
生成前缀为 password
的路由。我猜这个 overrides/takes 优先于 UrlHelper
.
中的 password_path
方法
关于为什么 returns /password.user
,每个路由方法都有一个可选的格式参数,指定请求的格式(例如 /password.html
、/password.json
等) .在您的情况下,resource_name
的值为 user
.
你能做什么?我建议您将 put
和 patch
方法与 :edit_user_password
前缀相关联,保持与 devise 生成的路由相同的结构。这样你就不会 override/hide devise 的 UrlHelper
中定义的 password_path
方法。
注意:在试验路线时,我不得不在某些时候重新启动我的服务器。因此,如果某些事情没有按预期发生,请尝试重新启动它。
我有一个带有普通用户模型的简单 Devise 安装。我确认默认路由一切正常(注册、丢失密码等),然后开始像这样自定义:
devise_for :users, :skip => [:sessions, :registrations, :passwords]
as :user do
get 'signin' => 'devise/sessions#new', :as => :new_user_session
post 'signin' => 'devise/sessions#create', :as => :user_session
delete 'signout' => 'devise/sessions#destroy', :as => :destroy_user_session
get 'register/cancel' => 'devise/registrations#cancel', :as => :cancel_user_registration
post 'register' => 'devise/registrations#create', :as => :user_registration
get 'register' => 'devise/registrations#new', :as => :new_user_registration
get 'account' => 'devise/registrations#edit', :as => :edit_user_registration
patch 'account' => 'devise/registrations#update'
put 'account' => 'devise/registrations#update'
delete 'account' => 'devise/registrations#destroy'
post 'password' => 'devise/passwords#create', :as => :user_password
get 'password/forgot' => 'devise/passwords#new', :as => :new_user_password
get 'password/reset' => 'devise/passwords#edit', :as => :edit_user_password
patch 'password' => 'devise/passwords#update'
put 'password' => 'devise/passwords#update'
end
然而,忘记密码页面会创建一个 POST 路径,如下所示:
<form class="new_user" id="new_user" action="/password.user" accept-charset="UTF-8" method="post">
...
</form>
从相应的观点来看:
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
使用默认的 Devise 路由,url 正确显示为 /users/password
,但使用我的自定义路由,我得到 /password.user
。好像只有这一条路。
我知道简单的解决方法是将 password_path(resource_name)
更改为 password_path
,但我想首先了解为什么会中断。
在深入研究 Devise 的源代码并进行一些试验之后,我想我已经找到了发生这种情况的原因。如果您查看 devise_for
为模型 :user
生成的路由,密码路由有一个前缀 user_password
。路由方法是 user_password_path
。那么 password_path
实际上是如何工作的呢?
new.html.erb
中调用的password_path
方法实际上并不是devise_for :user
生成的方法。它是一个以模型名称作为参数的辅助方法。例如,当传递 :user
时,它将如下所示:
password_path(:user) => user_password_path
此方法然后调用 user_password_path
,这是正确的方法。更多信息 here.
在你的例子中,你正在创建一个前缀为 user_password
的路由,但你也有这些路由:
patch 'password' => 'devise/passwords#update'
put 'password' => 'devise/passwords#update'
生成前缀为 password
的路由。我猜这个 overrides/takes 优先于 UrlHelper
.
password_path
方法
关于为什么 returns /password.user
,每个路由方法都有一个可选的格式参数,指定请求的格式(例如 /password.html
、/password.json
等) .在您的情况下,resource_name
的值为 user
.
你能做什么?我建议您将 put
和 patch
方法与 :edit_user_password
前缀相关联,保持与 devise 生成的路由相同的结构。这样你就不会 override/hide devise 的 UrlHelper
中定义的 password_path
方法。
注意:在试验路线时,我不得不在某些时候重新启动我的服务器。因此,如果某些事情没有按预期发生,请尝试重新启动它。