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
相关产品推荐
相关产品推荐

