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

如何在Ruby on Rails中包装ActiveRecord的attr_encrypted setter而避免无限循环

如何在Ruby on Rails中包装ActiveRecord的attr_encrypted setter而避免无限循环

我明白你现在遇到的问题——在重写attr_encrypted生成的ssn setter时,调用super导致了无限循环。让我们一步步分析问题并找到解决方案。

首先,先看你代码里的一个明显问题:你的Person类里重复定义了两次attr_encrypted :ssn, key: 'some_secret_key'。这完全没必要,而且可能会导致方法定义冲突,进而引发奇怪的循环问题,先把这行重复代码删掉,只保留一行。

接下来分析无限循环的核心原因:当你用prepend引入concern时,自定义的ssn=方法会先被执行,然后调用super(value)触发attr_encrypted原生的setter。但由于ActiveRecord属性处理机制和attr_encrypted实现的交互,加上重复定义的干扰,导致方法调用栈陷入了循环。

下面给你两种可行的解决方案:

方案一:使用before_save回调(推荐)

这种方式不需要重写ssn setter,而是在保存前同步ssn_last_four字段,既简单又彻底避免了循环问题:

module SsnLastFourConcern
  extend ActiveSupport::Concern

  included do
    before_save :sync_ssn_last_four
  end

  def ssn_last_four
    # 优先从解密后的完整SSN取后四位,没有的话用原字段的 legacy 值
    ssn? ? ssn[-4..] : super
  end

  private

  def sync_ssn_last_four
    # 只有当传入的SSN是完整9位格式时,同步后四位到ssn_last_four字段
    if ssn.present? && ssn.length == 9
      self.ssn_last_four = ssn[-4..]
    end
  end
end

对应的Person类保持简洁:

class Person < ApplicationRecord
  prepend SsnLastFourConcern
  attr_encrypted :ssn, key: 'some_secret_key'
end

这个方案的优势:

  • 完全规避了setter重写带来的循环风险
  • ssn_last_four始终和完整SSN保持同步,不会出现数据不一致
  • 手动解密encrypted_ssn列得到的依然是完整SSN,完全符合你的需求

方案二:安全重写ssn setter(如果必须重写)

如果你一定要通过重写setter来处理逻辑,可以绕过super,直接操作底层的加密字段,避免触发循环:

module SsnLastFourConcern
  extend ActiveSupport::Concern

  def ssn_last_four
    ssn? ? ssn[-4..] : super
  end

  def ssn=(value)
    if value.present? && value.length == 9
      self.ssn_last_four = value[-4..]
    end

    # 直接调用attr_encrypted的加密逻辑,避免触发super导致的循环
    encryptor = self.class.attr_encrypted_options[:ssn][:encryptor]
    encrypted_value = encryptor.encrypt(value, **self.class.attr_encrypted_options[:ssn])
    write_attribute(:encrypted_ssn, encrypted_value)
  end
end

不过这种方式直接依赖attr_encrypted的内部实现,后续如果gem版本更新可能需要调整代码,不如方案一健壮。

最后验证效果:不管用哪种方案,当你设置完整9位SSN时,ssn_last_four会自动同步为后四位;从数据库取出encrypted_ssn手动解密后,得到的依然是完整的SSN,完全满足你的业务需求。

备注:内容来源于stack exchange,提问作者Nedim Ramic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 09:03:01