Rails 7.0.4 API应用使用Devise测试时触发DisabledSessionError
解决Rails API模式下MiniTest使用Devise sign_in的会话错误
针对你遇到的问题,核心原因是Rails API模式默认禁用会话存储,而Devise的sign_in方法依赖会话保存登录状态,测试环境下就会触发DisabledSessionError。以下是几种可行的解决方案:
方案1:直接设置current_user(最简单)
跳过Devise的sign_in流程,直接给控制器实例赋值current_user,模拟登录状态:
修改测试代码:
test "should get index" do # 直接设置当前登录用户 @controller.instance_variable_set(:@current_user, users(:one)) get movies_url, as: :json assert_response :success end
如果多个测试都需要用,可以封装成辅助方法,在test/test_helper.rb中添加:
module ControllerTestHelper def sign_in_api(user) @controller.instance_variable_set(:@current_user, user) end end class ActiveSupport::TestCase include ControllerTestHelper end
之后测试里直接调用:
test "should get index" do sign_in_api users(:one) get movies_url, as: :json assert_response :success end
方案2:测试环境启用会话存储(适合坚持用Devise sign_in的场景)
如果必须使用Devise的sign_in方法,需要在测试环境中启用会话中间件:
- 在
config/environments/test.rb中添加会话配置:
config.session_store :cookie_store, key: '_cinema_app_session' config.middleware.use ActionDispatch::Cookies config.middleware.use config.session_store, config.session_options
- 在
config/initializers/devise.rb中调整会话跳过设置:
# 只跳过HTTP认证和Token认证的会话存储,允许测试环境使用会话 config.skip_session_storage = [:http_auth, :token_auth]
这种方法会在测试环境中启用会话,可能和API模式的无状态设计冲突,仅推荐特殊场景使用。
方案3:模拟API真实认证方式(最贴合生产场景)
如果你的API实际使用Token认证,测试时直接在请求头中携带认证Token:
- 确保用户Fixture包含认证Token(
test/fixtures/users.yml):
one: email: admin@cinema.com encrypted_password: <%= Devise.bcrypt(User, 'admin123') %> authentication_token: 'cinema-admin-token-001'
- 测试代码中携带Token请求:
test "should get index" do auth_token = users(:one).authentication_token get movies_url, as: :json, headers: { 'Authorization' => "Token token=#{auth_token}" } assert_response :success end
这种方式完全贴合API的无状态认证逻辑,是最推荐的长期解决方案。
内容的提问来源于stack exchange,提问作者Victor Rubia
相关产品推荐
相关产品推荐

