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

使用update_column更新ActiveRecord模型时如何仅保留paper-trail回调

解决paper_trail不记录update_columns操作的实现方案

update_columns方法默认会跳过所有Active Record回调和验证,直接执行数据库更新操作,而paper_trail的版本生成逻辑依赖Active Record的after_update等回调,所以默认不会记录update_columns的变更。


方案1:重写update_columns方法自动记录版本

单模型实现

直接在已经开启paper_trail的模型中添加以下代码即可:

class YourModel < ApplicationRecord
  has_paper_trail

  def update_columns(*args)
    # 提取要更新的属性键值对
    update_attrs = args.extract_options!
    args.each { |key| update_attrs[key] = public_send(key) }

    # 先执行原生更新逻辑,保存返回值
    update_success = super

    # 更新成功后手动生成版本记录
    if update_success && PaperTrail.enabled? && PaperTrail.request.enabled_for_model?(self.class)
      changeset = update_attrs.transform_values { |old_val| [old_val, public_send(_1)] }
      versions.create!(
        event: "update",
        object_changes: changeset,
        whodunnit: PaperTrail.request.whodunnit,
        **(PaperTrail.request.controller_info || {})
      )
    end

    update_success
  end
end

全局多模型复用实现

如果需要给所有开启paper_trail的模型都支持该功能,可以把逻辑抽为公共关注点:

  1. 新建app/models/concerns/paper_trail_update_columns_tracking.rb文件,写入以下代码:
module PaperTrailUpdateColumnsTracking
  extend ActiveSupport::Concern

  included do
    def update_columns(*args)
      update_attrs = args.extract_options!
      args.each { |key| update_attrs[key] = public_send(key) }

      update_success = super

      if update_success && PaperTrail.enabled? && PaperTrail.request.enabled_for_model?(self.class)
        changeset = update_attrs.transform_values { |old_val| [old_val, public_send(_1)] }
        versions.create!(
          event: "update",
          object_changes: changeset,
          whodunnit: PaperTrail.request.whodunnit,
          **(PaperTrail.request.controller_info || {})
        )
      end

      update_success
    end
  end
end
  1. 在需要的模型中引入即可:
class YourModel < ApplicationRecord
  has_paper_trail
  include PaperTrailUpdateColumnsTracking
end

方案2:手动触发版本记录(无需重写方法)

如果只有少数场景需要记录update_columns的变更,可以不用修改底层方法,每次调用后手动触发版本生成即可:

# 执行更新
your_record.update_columns(status: "completed", updated_at: Time.current)
# 手动生成paper_trail版本
your_record.paper_trail.save_with_version

该方案灵活性更高,适合不需要全量覆盖的场景,缺点是容易遗漏手动调用步骤


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 18:54:01