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

CircleCI+Rspec中添加where子句后ActiveRecord::Relation为空排查

问题根源及解决方案

核心问题分析

结合你描述的现象(本地正常、CircleCI测试失败,测试内调用过滤器正常但控制器内返回空),主要排查方向集中在以下几点:

1. 过滤器inject逻辑存在隐性bug

你的call方法中,inject块仅在过滤条件满足时返回处理后的作用域,条件不满足时未返回原作用域,会导致inject最终返回nil(Ruby块默认返回最后一行执行结果,未满足条件时无有效返回值)。虽然当前仅定义了一个过滤器,但如果后续新增过滤器或参数匹配异常,会直接导致作用域丢失。

2. 控制器与测试中传入的current_user实例类型不匹配

测试中调用过滤器时传入的是tech(Staff模型实例),但控制器中可能传入的是User模型实例(比如通过JWT解析得到的用户对象)。由于WorkOrder的technician关联的是Staff模型,用User实例做where(technician: user)查询自然无法匹配到数据。

3. 测试数据的Tenant隔离问题

CircleCI环境中,测试创建的assigned_work_order可能未正确关联到当前测试的tenant,而控制器中的查询带有current_tenant的作用域过滤,导致控制器内的基础作用域就不包含该工单,追加过滤后自然返回空。


具体修复方案

方案1:修复过滤器的inject逻辑

确保无论过滤条件是否满足,inject块始终返回有效的作用域:

def call(scope, params, current_user)
  FILTERS.keys.inject(scope.dup) do |current_scope, filter_key|
    filter = fetch_filter(filter_key)
    # 条件满足时返回过滤后的作用域,否则返回原作用域
    filter[:apply?].call(params) ? filter[:apply].call(current_scope, current_user) : current_scope
  end
end

方案2:统一控制器与测试的current_user实例类型

如果控制器中current_user是User模型,需关联到对应的Staff实例后再传入过滤器:

# 控制器内调用过滤器的代码
scope = current_tenant.work_orders.where(state: :in_progress)
@work_orders = WorkOrderPreviews::IndexFilter.new.call(scope, params, current_user.staff)

方案3:确保测试数据的Tenant关联正确性

  • 在WorkOrder工厂中强制关联当前Tenant:
    factory :work_order do
      tenant { Tenant.current } # 假设存在Tenant.current全局设置
      # ...其他属性
    end
    
  • 在测试中添加断言验证关联:
    context 'with user filter' do
      it 'should respond with the assigned work order when ?filter=current_user' do
        expect(assigned_work_order.tenant).to eq(tenant) # 验证工单属于当前测试租户
        # ...剩余测试代码
      end
    end
    

方案4:对齐测试与控制器的基础作用域

测试中使用与控制器一致的带Tenant过滤的基础作用域,避免测试与实际逻辑不一致:

scope = tenant.work_orders.where(state: 'in_progress') # 替换原WorkOrder.where(...)
filtered_results = WorkOrderPreviews::IndexFilter.new.call(scope, { filter: 'current_user' }, tech)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 13:45:24