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

如何在Rails的after_update回调中传递admin_id参数?

问题背景

我有一个UserProfile模型,代码如下:

class UserProfile < ApplicationRecord
  after_update :check_changes

  def check_changes
    AuditRecord.create(account_id: self.id, fields: self.saved_changes , account_type: 'UserProfile', admin_id: 3) if self.saved_changes?
  end
end

UserProfile的数据表结构:

iduser_idnamelast_name
11johndoe
22foobar

同时还有一个AuditRecord模型,数据表结构:

idaccount_typeaccount_idfieldadmin_id
1UserProfile1{}3
2UserProfile2{}3

AuditRecord用于保存用户资料的所有更新记录,但资料可能由不同管理员操作。目前在check_changes方法中admin_id固定为3,请问如何将操作的admin_id传递给该方法?


解决方案

方法1:实例变量传递

给UserProfile添加一个临时实例变量,在更新前赋值当前管理员ID,回调中直接取用:

# 修改UserProfile模型
class UserProfile < ApplicationRecord
  attr_accessor :current_admin_id
  after_update :check_changes

  def check_changes
    return unless saved_changes? && current_admin_id.present?
    AuditRecord.create(
      account_id: id,
      fields: saved_changes,
      account_type: 'UserProfile',
      admin_id: current_admin_id
    )
  end
end

# 业务代码中更新时传递ID
user_profile = UserProfile.find(1)
user_profile.current_admin_id = current_admin.id # current_admin为当前操作的管理员对象
user_profile.update(name: 'johnny')

方法2:带参数的回调(Rails 5+)

Rails 5及以上支持给回调传递参数,直接在触发更新时传入管理员ID:

# 修改UserProfile模型
class UserProfile < ApplicationRecord
  after_update -> { check_changes(admin_id) }, if: :saved_changes?

  def check_changes(admin_id)
    AuditRecord.create(
      account_id: id,
      fields: saved_changes,
      account_type: 'UserProfile',
      admin_id: admin_id
    )
  end
end

# 业务代码中更新
user_profile = UserProfile.find(1)
user_profile.update({ name: 'johnny' }, admin_id: current_admin.id)

方法3:线程局部变量(控制器全局传递)

如果操作在控制器中执行,用线程局部变量存储管理员ID,回调中直接读取:

# 管理员控制器中设置
class Admin::UserProfilesController < ApplicationController
  before_action :set_current_admin

  def update
    @user_profile.update(user_profile_params)
  end

  private
  def set_current_admin
    Thread.current[:current_admin_id] = current_admin.id
  end
end

# 修改UserProfile模型
class UserProfile < ApplicationRecord
  after_update :check_changes, if: :saved_changes?

  def check_changes
    admin_id = Thread.current[:current_admin_id]
    return unless admin_id.present?
    AuditRecord.create(
      account_id: id,
      fields: saved_changes,
      account_type: 'UserProfile',
      admin_id: admin_id
    )
  end
end

方法4:服务对象封装逻辑

把更新和审计逻辑封装到服务类中,直接传递管理员对象,避免回调参数传递的麻烦:

# 新建服务类 app/services/update_user_profile_service.rb
class UpdateUserProfileService
  def initialize(user_profile, admin, params)
    @user_profile = user_profile
    @admin = admin
    @params = params
  end

  def call
    @user_profile.transaction do
      if @user_profile.update(@params) && @user_profile.saved_changes?
        AuditRecord.create(
          account_id: @user_profile.id,
          fields: @user_profile.saved_changes,
          account_type: 'UserProfile',
          admin_id: @admin.id
        )
      end
    end
  end
end

# 业务代码中调用服务
user_profile = UserProfile.find(1)
UpdateUserProfileService.new(user_profile, current_admin, { name: 'johnny' }).call

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 07:55:19