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

Rails 7 API模式测试中手动设置User.current失效问题求助

问题原因

Rails集成测试(ActionDispatch::IntegrationTest)的每个请求都会在全新的线程中处理,你在测试主线程设置的User.current不会被共享到请求处理的线程中。如果User.current是基于类变量(如@@current)实现的,多线程环境下还会出现变量被意外重置的问题。

解决方案

1. 修复User.current的实现(改用线程局部变量)

确保User.current使用线程局部存储,避免多线程冲突:

class User < ApplicationRecord
  def self.current=(user)
    Thread.current[:current_user] = user
  end

  def self.current
    Thread.current[:current_user]
  end
end

2. 在测试请求中传递用户标识,在控制器中设置User.current

修改测试用例,通过请求头传递测试用户ID:

require 'test_helper'
class ThingControllerTest < ActionDispatch::IntegrationTest
  test "call method my_method" do
    me = users(:me)
    get "/api/users/#{me.id}/do-the-thing", headers: { 'X-Test-User-Id' => me.id.to_s }
    assert_response :success
  end
end

更新ApplicationController的认证逻辑,在测试环境下读取请求头并设置User.current:

class ApplicationController < ActionController::Base
  before_action :authenticate_user

  def authenticate_user
    if Rails.env.test?
      if test_user_id = request.headers['X-Test-User-Id']
        User.current = User.find(test_user_id)
      end
      return User.current
    end
    # 非测试环境的认证逻辑
  end
end

替代方案:使用测试辅助方法封装

如果需要在多个测试中复用,可以在test_helper.rb中添加辅助方法:

class ActionDispatch::IntegrationTest
  private

  def headers_with_current_user(user)
    { 'X-Test-User-Id' => user.id.to_s }
  end
end

然后测试用例可以简化为:

test "call method my_method" do
  me = users(:me)
  get "/api/users/#{me.id}/do-the-thing", headers: headers_with_current_user(me)
  assert_response :success
end
验证

修改后,请求处理线程会通过请求头获取用户ID并设置User.current,此时ThingController#the_thing中的User.current就能正确获取到测试用户,不会再为nil。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 04:15:23