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

FactoryBot创建Rollout时触发update_attribute栈溢出错误排查

Rails RSpec测试中FactoryBot设置percent_enabled触发栈溢出问题

运行RSpec测试时,只要在FactoryBot的rollout工厂里设置percent_enabled { 0 },创建实例就会抛出SystemStackError(栈溢出),错误栈指向rollout.rb第60行的percent_enabled=方法。注释掉这个赋值语句后测试正常,已经试过bundle update没用。

相关代码

工厂代码(rollouts.rb)

FactoryBot.define do
  factory :rollout do
    name { Faker::IndustrySegments.industry.parameterize.underscore }
    percent_enabled { 0 }
    offset { 0 }
    green_list { [] }
    red_list { [] }
    resource_type { 'User' }
    trait :with_user do
      resource_type { 'User' }
    end
  end
end

模型代码(rollout.rb)

class Rollout < ApplicationRecord
  before_create :set_offset
  before_validation :uppercase_resource_type

  validates :name, presence: true, uniqueness: { case_sensitive: false }
  validates_inclusion_of :percent_enabled, in: 0..100
  validates :resource_type, presence: true, inclusion: { in: %w[User Role Instrument Profile] }

  # ...其他方法...
end

错误信息

Failures:

  1) Rollout a valid Rollout that has working validations is valid with valid attributes
     Failure/Error: update_attribute(:percent_enabled, num)

     SystemStackError:
       stack level too deep
     # ./app/models/rollout.rb:60:in `percent_enabled='
     # ./app/models/rollout.rb:60:in `percent_enabled='
     ...

测试代码(rollout_spec.rb)

RSpec.describe Rollout, type: :model do
  describe 'a valid Rollout' do
    let(:rollout) { create(:rollout, :with_user) }

    context 'that has working validations' do

      it 'is valid with valid attributes' do
        print(rollout)

        expect(rollout).to be_valid
      end
   end
end

问题原因与解决方案

栈溢出的核心原因是自定义的percent_enabled=方法内部发生了无限递归调用。虽然你提供的模型代码里没显示这个方法,但错误明确指向第60行的该方法,说明你肯定在模型里重写了这个setter。

比如错误的写法(会递归调用自己):

def percent_enabled=(num)
  self.percent_enabled = num.to_i # 这里每次赋值都会再次调用这个方法,无限循环
end

正确的写法应该绕过自定义setter,直接操作数据库列或者调用父类方法:

# 方法一:直接操作属性哈希
def percent_enabled=(num)
  self[:percent_enabled] = num.to_i
end

# 方法二:调用父类的setter方法
def percent_enabled=(num)
  super(num.to_i)
end

按上述方式修改rollout.rb第60行的percent_enabled=方法后,重新运行测试即可解决栈溢出问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 22:23:11