使用Devise Token Auth登录Rails应用触发500内部服务器错误
解决Devise Token Auth登录时的NoMethodError(undefined method `each')
我之前也碰到过完全一样的问题,咱们先从根源入手解决它:从你的请求日志和调用栈来看,问题核心是提交的参数结构不符合Devise Token Auth的预期。你提交的参数是这样的:
{"login":"admin", "password":"[FILTERED]", "session":{"login":"admin", "password":"[FILTERED]"}}
Devise Token Auth的params_for_resource方法(就是报错的那个方法)会尝试遍历资源参数,但它期望参数要么是顶层的登录/密码字段,要么是嵌套在和你的用户模型名一致的键下(比如模型是User的话,应该是{"user": {"login": "admin", "password": "xxx"}}),而不是嵌套在session键里。当它拿到错误的参数结构时,就会在非可迭代对象上调用each方法,从而抛出这个错误。
快速解决方案
方案1:调整前端请求的参数结构
最简单的方法是直接修改前端提交的参数,去掉session嵌套:
{"login":"admin", "password":"your_password_here"}
或者遵循Rails参数惯例,嵌套在模型名对应的键下(比如用户模型是User):
{"user": {"login":"admin", "password":"your_password_here"}}
方案2:后端重写params_for_resource方法(无法修改前端时用)
如果没办法调整前端参数,可以在后端自定义控制器,重写这个方法来适配现有参数结构:
- 创建自定义的SessionsController,继承自DeviseTokenAuth的控制器:
# app/controllers/auth/sessions_controller.rb class Auth::SessionsController < DeviseTokenAuth::SessionsController private def params_for_resource # 从session键提取参数,同时保留顶层的登录密码字段 params.fetch(:session, {}).merge(params.permit(:login, :password)) end end
- 修改路由,指向这个自定义控制器:
# config/routes.rb mount_devise_token_auth_for 'User', at: 'auth', controllers: { sessions: 'auth/sessions' }
补充说明
你的Devise Token Auth版本是0.1.43,属于比较旧的版本。如果上面的方案都没解决问题,可以考虑升级到较新的稳定版本(记得先备份代码,避免兼容性问题),新版本大概率修复了这类参数解析的边界问题。
内容的提问来源于stack exchange,提问作者user9867785
相关产品推荐
相关产品推荐

