【问题标题】:How do I set current_user in middleware?如何在中间件中设置 current_user?
【发布时间】:2013-12-27 20:45:12
【问题描述】:

要为我的问题提供更多背景信息,请参阅此 Github 问题 - https://github.com/getsentry/raven-ruby/issues/144

我正在使用raven,它是一个错误记录器。如果用户已登录,我想为current_user 添加 id。我收到的答案是

这应该通过您的中间件或类似的地方来完成。

其中 this 表示在 Raven 中设置 current_user。

我已经阅读了有关中间件的信息,但仍然无法弄清楚如何将current_user 合二为一。

【问题讨论】:

    标签: ruby-on-rails devise sentry


    【解决方案1】:

    我对@9​​87654321@ 不太了解,但下面是一种方法,我们可以使用它在整个应用程序的请求中访问当前用户。

    我们创建了一个类,它充当缓存,从当前线程插入/检索数据

    class CustomCache
        def self.namespace
          "my_application"
        end
    
        def self.get(res)
          Thread.current[self.namespace] ||= {}
            val = Thread.current[self.namespace][res] 
            if val.nil? and block_given?
                val = yield
                self.set(res, val) unless val.nil?
            end
            return val
        end
    
        def self.set(key, value)
            Thread.current[self.namespace][key] = value
        end
    
        def self.reset
          Thread.current[self.namespace] = {}
        end
      end
    

    然后,当收到请求时,会检查当前会话,然后将用户的模型插入缓存中,如下所示

    def current_user
      if defined?(@current_user)
        return @current_user
      end
      @current_user = current_user_session && current_user_session.record
      CustomCache.set(:current_user, @current_user)
      return @current_user
    end
    

    现在,您可以使用以下代码从应用程序中的任何位置检索当前用户,

    CustomCache.get(:current_user)
    

    我们还确保在请求被处理之前和之后重置缓存,所以我们这样做,

    CustomCache.reset
    

    希望这会有所帮助。

    【讨论】:

    • 这看起来很有趣。我想知道 Devise 是否有可以在中间件中使用的 current_user 方法。
    【解决方案2】:

    对于 Rails 应用程序,我仅在 before_action 内的 ApplicationController 中设置 Raven (Sentry) 上下文就成功了:

    # application_controller.rb
    class ApplicationController < ActionController::Base
      before_action :set_raven_context
    
      def set_raven_context
        # I use subdomains in my app, but you could leave this next line out if it's not relevant
        context = { account: request.subdomain }
        context.merge!({ user_id: current_user.id, email: current_user.email }) unless current_user.blank?
        Raven.user_context(context)
      end
    end
    

    这是因为 raven Rack 中间件会在每次请求后清除上下文。 See here. 但是,它可能不是最有效的,因为即使在大多数不会导致异常的情况下,您也在设置上下文。但无论如何,它并没有那么昂贵的操作,而且它会让你走得很远,而无需真正需要注入新的 Rack 中间件或任何东西。

    【讨论】:

    • 这似乎是个不错的方法。我目前没有使用 Raven,所以无法尝试,但这是我正在寻找的解决方案。一旦我有机会与 Raven 一起尝试,我会将您的解决方案标记为正确。
    • 这个线程安全吗?似乎在类上设置它可能会导致另一个线程中的请求在第一个请求仍在运行时覆盖该值?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 2018-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    相关资源
    最近更新 更多