【问题标题】:How to get the current_user in a model observer?如何在模型观察者中获取 current_user?
【发布时间】:2011-11-03 02:34:51
【问题描述】:

鉴于以下模型:

Room (id, title)
RoomMembers (id, room_id)
RoomFeed, also an observer

更新房间标题时,我想创建一个 RoomFeed 项目,显示进行更新的用户是谁。

@room.update_attributes(:title => "This is my new title")

问题在于我的 RoomFeed 观察员:

def after_update(record)
   # record is the Room object
end

我无法获取刚刚进行更新的人的 user.id。我该怎么做呢?有没有更好的更新方法让我得到 current_user?

【问题讨论】:

标签: ruby-on-rails ruby-on-rails-3 activerecord observer-pattern


【解决方案1】:

我认为您正在寻找的是观察者内部的 room.updated_by。如果您不想保留 updated_by,只需将其声明为 attr_accessor。在推送更新之前,请确保将 current_user 分配给 updated_by,可能来自您的控制器。

【讨论】:

    【解决方案2】:

    这是一个典型的“关注点分离”问题。

    current_user 存在于控制器中,Room 模型应该对此一无所知。也许 RoomManager 模型可以处理谁在更改门上的名称...

    同时一个快速而肮脏的解决方案是在 Room.rb 中抛出一个(非持久性)属性来处理 current_user....

    # room.rb
    class Room
      attr_accessor :room_tagger_id
    end
    

    并在更新@room 时在参数中传递您的 current_user。

    这样你就找到了罪魁祸首! :

    def after_update(record)
       # record is the Room object
       current_user = record.room_tagger_id
    end
    

    【讨论】:

      【解决方案3】:

      创建以下内容

      class ApplicationController
        before_filter :set_current_user
      
        private
        def set_current_user
          User.current_user = #however you get the current user in your controllers
        end
      end
      
      class User
         ...
         def self.current_user
           @@current_user
         end
         def self.current_user= c
           @@current_user = c
         end
         ...
      end
      

      然后使用...

      User.current_user wherever you need to know who is logged in.  
      

      请记住,当您的类从非 Web 请求(如 rake 任务)调用时,该值不能保证设置,因此您应该检查 .nil?

      【讨论】:

      • 我喜欢这个解决方案,因为它可以很好地分离关注点。 Room 模型不需要知道 current_user,如果需要,观察者可以访问它。我自己也使用这种精确的方法。如果未设置 current_user,我默认为 SYSTEM 用户(例如,来自控制台内的更新继续工作,并且仍然清晰标记)。
      • 这不是一个好主意,因为在生产中类变量的值不会在请求之间被清除。而且这种方法不是线程安全的。
      • 如果您在 before 过滤器中执行此操作,那么它应该在每次调用开始时执行,因此您可以在每个请求使用单个线程运行的 Rails 环境中。
      【解决方案4】:

      【讨论】:

      • 阅读该链接上的 cmets。人们说这样做是一个非常糟糕的主意,因为下一个请求可能会重用您传递给 User.current 的相同用户详细信息。
      【解决方案5】:

      更新用户.rb

      class User < ActiveRecord::Base
        cattr_accessor :current
      end
      

      更新 application_controller.rb

      class ApplicationController
        before_filter :set_current_user
      
        private
        def set_current_user
          User.current = current_user
        end
      end
      

      然后您可以在任何地方通过User.current 获取登录用户。我正在使用这种方法在观察者中完全访问用户。

      【讨论】:

      • cattr_accessor :current 应该是 attr_accessor :current
      • @ajt 不,这是一个类属性,这就是为什么 cattr
      • 这太疯狂了。您将自己打开 1) 攻击,其中下一个请求重用以前请求的旧 User.current 2) 我们甚至不谈论运行线程服务器 3) 在开发模式下运行时阻止 ActiveRecord 正确重新加载其关联缓存
      猜你喜欢
      • 2012-02-15
      • 1970-01-01
      • 2016-02-20
      • 2023-04-10
      • 1970-01-01
      • 2012-09-05
      • 1970-01-01
      • 2021-12-14
      • 1970-01-01
      相关资源
      最近更新 更多