You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Devise登出路由错误指向UsersController而非SessionsController求助

问题:Devise API登出请求被错误路由至UsersController

问题现象

登录功能正常,POST请求/api/users/sign_in能正确路由到API::SessionsController#create;但执行登出测试时,DELETE请求/api/users/sign_out被错误路由到API::UsersController,触发AbstractController::ActionNotFound错误(提示该控制器不存在destroy动作)。查看路由列表显示destroy_api_user_session应该指向api/sessions#destroy,同时项目中存在api/users的RESTful路由。

相关代码片段

测试登录代码

p "sign in URL: #{path + api_user_session_path}"
post (path + api_user_session_path), params: { unlock: encrypted_unlock }

登录终端输出

"sign in URL: http://api.example.com/api/users/sign_in"
Started POST "/api/users/sign_in" for 127.0.0.1 at 2023-12-06 15:36:51 -0500
   (3.7ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
Processing by API::SessionsController#create as JSON

测试登出代码

p "sign out url: #{path + destroy_api_user_session_path}"
delete (path + destroy_api_user_session_path)

登出终端报错

"sign out url: http://api.example.com/api/users/sign_out"
Started DELETE "/api/users/sign_out" for 127.0.0.1 at 2023-12-06 15:36:51 -0500
  
AbstractController::ActionNotFound (The action 'destroy' could not be found for API::UsersController

routes.rb配置

Rails.application.routes.draw do
  namespace :api, defaults: { format: :json } do
    ...
    devise_for :users, controllers: { sessions: 'api/sessions' }
    ...
  end
end

原因分析

核心问题是Rails路由的匹配顺序:Rails会按照路由文件中定义的顺序从上到下匹配请求。如果resources :users(生成RESTful路由,包含DELETE /api/users/:id)的定义在devise_for :users之前,那么当请求DELETE /api/users/sign_out时,Rails会把sign_out识别为:id参数,优先匹配到users#destroy路由,而不是Devise生成的session#destroy路由。

解决方案

方案1:调整路由定义顺序(推荐)

把devise_for :users的定义放在resources :users之前,让Devise的登出路由先被匹配:

Rails.application.routes.draw do
  namespace :api, defaults: { format: :json } do
    # 先定义Devise路由,确保优先匹配
    devise_for :users, controllers: { sessions: 'api/sessions' }
    # 再定义其他RESTful路由
    resources :users
    ...
  end
end

方案2:添加路由约束

如果无法调整顺序,可以给resources :users添加约束,排除sign_out这类Devise路径,避免被误匹配:

Rails.application.routes.draw do
  namespace :api, defaults: { format: :json } do
    resources :users, constraints: { id: /\d+/ } do
      # 仅匹配数字ID,排除sign_out这类字符串
    end
    devise_for :users, controllers: { sessions: 'api/sessions' }
    ...
  end
end

内容的提问来源于stack exchange,提问作者Jeremy Thomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 13:55:26