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

Rails 6.1+中使用destroy_async时如何为PaperTrail传递whodunnit?

问题描述

我在基于Rails 7.2的应用中使用PaperTrail gem追踪模型变更(包括删除操作),希望用上Rails 6.1引入的destroy_async特性。后台删除功能正常,但异步执行销毁时,PaperTrail无法捕获whodunnit。

我试过用PaperTrail.request(whodunnit: current_user)包裹销毁调用:

PaperTrail.request(whodunnit: current_user) do
  object.destroy
end

但使用destroy_async时没法正确关联whodunnit。我还试过自定义后台处理删除并显式传递whodunnit,虽然可行,但不如内置的destroy_async简洁。

请问有没有清晰的方法,在使用destroy_async时为PaperTrail传递whodunnit?


解决方案

扩展destroy_async传递whodunnit

destroy_async本质是通过ActiveJob执行异步销毁,我们可以扩展模型的destroy_async方法,将当前上下文的whodunnit传入Job,再在Job执行时为PaperTrail设置该值,既保留内置方法的简洁性,又能正确记录操作人。

  1. 创建一个Concern文件(app/models/concerns/paper_trail_destroy_async.rb):
module PaperTrailDestroyAsync
  extend ActiveSupport::Concern

  included do
    # 重写destroy_async,支持传递whodunnit参数
    def destroy_async(whodunnit: PaperTrail.request.whodunnit)
      self.class.destroy_async_job_class.new(id, whodunnit: whodunnit).enqueue
    end

    # 自定义销毁Job,执行时设置PaperTrail的whodunnit
    class DestroyAsyncJob < ActiveJob::Base
      def perform(record_id, whodunnit: nil)
        record = self.class.model_class.find(record_id)
        PaperTrail.request(whodunnit: whodunnit) do
          record.destroy
        end
      end

      private

      def self.model_class
        @model_class ||= name.deconstantize.constantize
      end
    end
  end
end
  1. 在需要使用的模型中引入该Concern:
class Post < ApplicationRecord
  include PaperTrailDestroyAsync
  has_paper_trail
end
  1. 确保控制器上下文已设置whodunnit(可在ApplicationController全局配置):
class ApplicationController < ActionController::Base
  before_action :set_paper_trail_whodunnit

  private

  def set_paper_trail_whodunnit
    # 这里用current_user的ID或邮箱作为whodunnit标识,按需调整
    PaperTrail.request.whodunnit = current_user&.id.to_s
  end
end
  1. 直接调用destroy_async即可自动传递whodunnit:
# 控制器中调用
@post.destroy_async

# 也可显式指定whodunnit(覆盖上下文值)
@post.destroy_async(whodunnit: admin_user.id)

原理说明

  • 重写的destroy_async会捕获当前PaperTrail请求上下文的whodunnit,作为参数传入自定义的DestroyAsyncJob。
  • Job执行时,通过PaperTrail.request包裹销毁操作,临时设置whodunnit,让PaperTrail能正确记录该异步操作的发起者。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 02:23:18