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

Rails自定义EncryptedTextType导致加载记录后始终标记为脏

问题成因

你遇到的是Rails自定义加密类型的典型脏检查误判问题,根因有两个:

  1. ActiveRecord对自定义类型字段的脏检查默认逻辑是:将当前内存中存储的明文属性值通过serialize方法转为密文后,和数据库中存储的原始密文值做对比,二者相等才会判定为未变更。
  2. 工业级加密实现都会默认使用随机IV(初始化向量)/随机盐,保证相同明文每次加密得到的密文完全不同,所以即使你没修改过access_key的明文,每次调用serialize得到的新密文永远和数据库中存储的旧密文不一致,就会被判定为字段变更。
    你在changes输出中看到两个access_key值完全相同,是因为changes方法返回的是经过deserialize转换后的明文值,和底层脏检查用的密文判断维度不同。
修复方案

最优方案是重写自定义类型的changed_in_place?方法,直接对比明文的一致性,跳过密文对比逻辑,修改后的类型代码如下:

class EncryptedTextType < ActiveRecord::Type::Text
  def deserialize(encrypted_value)
    return unless encrypted_value

    Encryptor.decrypt(encrypted_value)
  end

  def serialize(plain_value)
    return unless plain_value

    Encryptor.encrypt(plain_value)
  end

  # 新增脏检查判断逻辑,直接对比明文是否修改
  def changed_in_place?(raw_old_value, new_value)
    old_value = deserialize(raw_old_value)
    old_value != new_value
  end
end

ActiveRecord::Type.register(:encrypted_text, EncryptedTextType)

该方案不需要修改加密器逻辑,也不会影响加密安全性,修改后重启服务即可解决误判脏数据的问题。

内容的提问来源于stack exchange,提问作者Luiz E.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 23:24:04