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

RSpec测试中更新Record属性为{}未生效的问题排查求助

问题:如何正确设置Record的attribute属性为{}并在查询中匹配?

我需要将Record类型记录record的attribute属性设置为{},尝试了以下操作但遇到问题:

已尝试的操作

  • spec文件中:
    record.update_attribute(attribute: {})
    record.attribute = {}
    
  • FactoryBot文件中:
    trait :update_attr do
      attribute {{}}
    end
    

遇到的问题

  • 测试调用的脚本中,使用Record.where(attribute: {})无法找到目标记录,推测是该属性存在默认值
  • spec文件内打印记录时,attribute显示为{},但脚本中查询返回的记录该属性是已填充的默认值,并非{}
  • 已检查FactoryBot文件,未找到该属性的默认值设置

示例代码

spec文件

require 'rails_helper'
require_relative Rails.root.join('script/test.rb')

RSpec.describe FixRecord do
  let(:record) { FactoryBot.create(:record) }

  subject { described_class.call }

  describe 'class#call' do
    before do
      preset.configurations = {}
    end
    it 'fixes record' do
      # 此处打印会显示记录ID及attribute为{}
      puts 'record', preset.attribute, record.id
      subject
      expect(preset.attribute).to eq({foo:'bar'})
    end
  end
end

脚本文件

class ResetError < StandardError; end

BATCH_SIZE = 1000

def self.call
  new.call
end

def call
  # 此处调用Record.find(x).attribute返回已填充的属性而非{}
  binding.pry

  Record.where("attribute=?", "{}") do |record|
    record.update(attribute: {foo: 'bar'})
  end
end

解决思路及方案

1. 定位默认值来源

FactoryBot中无默认值设置,需排查其他位置:

  • 数据库层面:检查Record对应的数据库表,确认attribute字段是否设置了JSON类型的默认值(如'{"key": "default_val"}')
  • 模型层面:查看Record模型代码,是否存在类似attribute :attribute, default: -> { { default_key: 'default_val' } }的默认值定义

2. 正确设置空对象并持久化

要确保{}被真正写入数据库,避免被默认值覆盖:

# 方式1:直接更新数据库字段,跳过模型回调和验证
record.update_columns(attribute: {})

# 方式2:若需触发模型回调,先赋值再强制保存
record.attribute = {}
record.save(validate: false) # 若有验证拦截,可临时跳过

在FactoryBot中,可通过after(:create)确保值被写入:

trait :update_attr do
  attribute { {} }
  after(:create) do |record|
    record.update_columns(attribute: {})
  end
end

3. 正确查询空JSON对象

不同数据库对空JSON的查询语法有差异,避免直接字符串匹配的兼容性问题:

PostgreSQL

# 推荐写法
Record.where(attribute: {})
# 或原生SQL写法
Record.where("attribute = '{}'::jsonb")

MySQL

Record.where("attribute = '{}'")

4. 验证数据库实际存储值

在脚本的binding.pry中,直接查询数据库确认字段真实值:

sql = "SELECT attribute FROM records WHERE id = #{record.id}"
raw_value = ActiveRecord::Base.connection.execute(sql).first['attribute']
puts raw_value # 确认是否为真正的空JSON对象{}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 03:52:40