Rails:在模型中访问当前用户会话

5

维护一个部署在Apache上的Rails v2.3.8应用程序,使用mod_passenger。

我需要在其中一个模型(确切地说是Auditor观察者)中访问当前用户会话。我知道这违反了MVC原则。但是我必须违反它,因为我有一个观察者需要知道当前登录的用户。我有很多控制器,将调用Auditor记录器放置在那里不太DRY。

我只是想能够调用User.current并返回当前已登录用户会话。然而,我遇到了缓存/线程安全问题。原始作者使用类变量(@@current)来存储当前用户。但这不是线程安全的,所以我将其转换为以下内容:

class User < AR:Base
  ...
  def self.current
    Thread.current[:user]
  end

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

所以它应该是线程安全的。在审计观察器中,我有一个调用:
Auditor(subject, action, object)

我在主题中传递User.current。

这段代码在开发中运行良好,但在生产中,我从User.current得到了错误的值。有时我会得到另一个已登录用户的记录而不是当前用户的记录。因此,仍然存在一些线程安全/类缓存问题,但我无法找出如何解决它。

有什么建议吗? 谢谢

1个回答

3

ActiveRecord和ActionPack是完全不同的,因此您无法在模型中访问session/cookies。如果您需要当前用户,有两个选项。

选项1-将当前用户传递给模型

在您的控制器中:

def index
    Audit.get_current_user(current_user)
    #where audit is your model that you will send the current_user to
end 

选项2 - 拥有一个用户模型,在用户对象被修改后执行操作。

在您的用户模型中:

before_save :adjust_user

def adjust_user
    #self will be the object that was just modified aka the current user
end 

这就是为什么我创建了当前的getter/setter方法,它们是线程安全的,它允许我存储/获取当前用户。问题出现在对User.current的调用被缓存了(我认为)。 - Swartz
对于选项1:我可以直接从控制器方法传递current_user,不确定为什么需要get_current_user()。但是我特意避免从控制器进行许多次Auditor()调用,因为有很多地方需要这种类型的调用。Observer工作更加干净利落。 - Swartz
对于选项2:我不明白你的意思……用户对象并不是唯一一个被修改的东西。我有各种对象可以让已登录的用户进行修改(如策略、权限等)。把审核员视为活动记录器。用户可以CRUD策略、权限等。因此,我仍然需要将current_user传递给审核员模型。 - Swartz
我能说的是,Rails的MVC模式实际上不允许从模型中获取用户信息,除非有一些插件/宝石可以实现这个功能。 - thenengah
您还可以使用 :touch => :model_name 来更新关联。 - thenengah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接