ruby-on-rails 如何在Rails的ActiveRecord回调中获取Devise的current_user?

gstyhher  于 2022-12-05  发布在  Ruby
关注(0)|答案(4)|浏览(138)

我正在使用Devise和Rails 3.2.16。我想自动插入谁创建了一个记录,谁更新了一个记录。所以我在模型中有这样的东西:

before_create :insert_created_by
before_update :insert_updated_by

private
def insert_created_by
  self.created_by_id = current_user.id
end
def insert_updated_by
  self.updated_by_id = current_user.id
end

问题是我得到错误undefined local variable or method 'current_user',因为current_user在回调中不可见。我如何自动插入谁创建和更新了此记录?
如果在Rails4.x中有一种简单的方法可以做到这一点,我将进行迁移。

lb3vh1jj

lb3vh1jj1#

编辑@HarsHarl的答案可能会更有意义,因为这个答案非常相似。
使用Thread.current[:current_user]方法,您必须进行此调用来为每个请求设置User。您可以选择使用skip_before_filter跳过设置用户,或者不将before_filter放在ApplicationController中,而是将其设置在需要current_user的控制器中。
模块化方法是将created_by_idupdated_by_id的设置移动到关注点,并将其包含在您需要使用的模型中。

    • 可审核的模块:**
# app/models/concerns/auditable.rb

module Auditable
  extend ActiveSupport::Concern

  included do 
    # Assigns created_by_id and updated_by_id upon included Class initialization
    after_initialize :add_created_by_and_updated_by

    # Updates updated_by_id for the current instance
    after_save :update_updated_by
  end

  private

  def add_created_by_and_updated_by
    self.created_by_id ||= User.current.id if User.current
    self.updated_by_id ||= User.current.id if User.current
  end

  # Updates current instance's updated_by_id if current_user is not nil and is not destroyed.
  def update_updated_by
    self.updated_by_id = User.current.id if User.current and not destroyed?
  end
end
    • 用户模型:**
#app/models/user.rb
class User < ActiveRecord::Base
  ...

  def self.current=(user)
    Thread.current[:current_user] = user
  end

  def self.current
    Thread.current[:current_user]
  end
  ...
end
    • 应用程序控制器:**
#app/controllers/application_controller

class ApplicationController < ActionController::Base
  ...
  before_filter :authenticate_user!, :set_current_user

  private

  def set_current_user
    User.current = current_user
  end
end
    • 范例用法:**在其中一个模型中包含auditable模块:
# app/models/foo.rb
class Foo < ActiveRecord::Base
  include Auditable
  ...
end

Foo模型中包含Auditable concern会在初始化时将created_by_idupdated_by_id分配给Foo的示例,这样您就可以在初始化后立即使用这些属性,并且它们会在after_save回调时持久保存到foos表中。

ldxq2e6h

ldxq2e6h2#

另一种方法是这样的,

class User
class << self
  def current_user=(user)
    Thread.current[:current_user] = user
  end

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

class ApplicationController
  before_filter :set_current_user

  def set_current_user
    User.current_user = current_user
  end
end
yacmzcpb

yacmzcpb3#

current_user不能从Rails中的模型文件中访问,只能从控制器、视图和助手中访问。虽然,通过类变量你可以实现这一点,但这不是一个好的方法,因为你可以在他的模型中创建两个方法。当从控制器创建操作调用时,将当前用户和字段名发送到该模型,例如:

Contoller code
def create
  your code goes here and after save then write
  @model_instance.insert_created_by(current_user)
end

而且在模型编写中

def self.insert_created_by(user)
  update_attributes(created_by_id: user.id)
end

其他方法相同

xytpbqjk

xytpbqjk4#

只需在模型中创建一个属性访问器,并在记录保存到控制器中时初始化它,如下所示

# app/models/foo.rb
class Foo < ActiveRecord::Base
  attr_accessor :current_user
  before_create :insert_created_by
  before_update :insert_updated_by

  private
   def insert_created_by
    self.created_by_id = current_user.id
  end
  def insert_updated_by
   self.updated_by_id = current_user.id
  end
end
# app/controllers/foos_controller.rb
class FoosController < ApplicationController
 def create
  @foo = Foo.new(....)
  @foo.current_user = current_user
  @foo.save
 end
end

相关问题