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

RoR中更新记录时保存当前用户ID的问题求助

Hey Chris,我来帮你搞定这个Devise更新记录时无法把current_user ID存入modified_by字段的问题!下面是几个实用的解决方案,你可以根据项目情况选:

方案一:控制器传递current_user + 模型回调

这是最直接的方式,核心思路是在控制器的更新动作里把current_user传给模型,再通过回调自动赋值:

1. 模型层修改

在需要审计的模型里添加一个临时属性接收current_user,再用before_save回调处理创建/更新时的字段赋值:

class YourModel < ApplicationRecord
  # 临时属性,用来接收控制器传来的current_user
  attr_accessor :current_user

  # 保存前触发,同时处理创建和更新场景
  before_save :set_audit_fields

  private

  def set_audit_fields
    # 创建时赋值created_by(如果你需要的话)
    self.created_by = current_user.id if current_user && new_record?
    # 每次保存(包括更新)都赋值modified_by
    self.modified_by = current_user.id if current_user
  end
end

2. 控制器层修改

在create和update动作里,把current_user赋值给模型的临时属性:

def create
  @your_model = YourModel.new(your_model_params)
  @your_model.current_user = current_user # 关键:传递current_user
  if @your_model.save
    redirect_to @your_model, notice: '创建成功'
  else
    render :new
  end
end

def update
  @your_model = YourModel.find(params[:id])
  @your_model.current_user = current_user # 关键:更新时也要传
  if @your_model.update(your_model_params)
    redirect_to @your_model, notice: '更新成功'
  else
    render :edit
  end
end

# 强参数要排除created_by和modified_by,避免手动赋值被覆盖
def your_model_params
  params.require(:your_model).permit(:name, :description) # 只允许业务字段
end
方案二:用Concern复用审计逻辑

如果多个模型都需要记录created_by/modified_by,用Rails的Concern可以避免重复代码:

1. 创建Auditable Concern

在app/models/concerns/auditable.rb里定义通用逻辑:

module Auditable
  extend ActiveSupport::Concern

  included do
    attr_accessor :current_user
    before_save :set_audit_fields
  end

  private

  def set_audit_fields
    self.created_by = current_user.id if current_user && new_record?
    self.modified_by = current_user.id if current_user
  end
end

2. 模型中引入Concern

class YourModel < ApplicationRecord
  include Auditable # 一行代码搞定审计逻辑
end

控制器的修改和方案一完全一样,不用重复写回调代码。

方案三:线程变量传递current_user(多模型场景推荐)

如果不想在每个控制器里手动赋值current_user,可以用线程变量全局传递,注意线程安全:

1. 全局控制器设置

在ApplicationController里添加钩子,把current_user存入线程变量:

class ApplicationController < ActionController::Base
  before_action :set_current_user_to_thread
  after_action :clear_current_user_from_thread

  private

  def set_current_user_to_thread
    Thread.current[:current_user] = current_user
  end

  # 必须在请求结束后清除,避免多线程环境下数据串混
  def clear_current_user_from_thread
    Thread.current[:current_user] = nil
  end
end

2. 模型层直接使用线程变量

class YourModel < ApplicationRecord
  before_save :set_audit_fields

  private

  def set_audit_fields
    current_user = Thread.current[:current_user]
    self.created_by = current_user.id if current_user && new_record?
    self.modified_by = current_user.id if current_user
  end
end

这种方式不需要修改任何控制器代码,适合多个模型都需要审计的项目。

关键注意事项
  • 检查回调时机:如果之前只用了before_create,那更新时不会触发,一定要换成before_save或者单独加before_update
  • 强参数必须排除created_by和modified_by,否则前端传值(或不传)会覆盖我们的手动赋值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:05:25