【问题标题】:How to set in a middleware a variable accessible in all my application?如何在中间件中设置一个可在我的所有应用程序中访问的变量?
【发布时间】:2011-03-04 09:54:27
【问题描述】:

我正在使用 Ruby on Rails 3,并且我正在尝试使用中间件来设置变量 @variable_name 稍后在控制器中可访问。

例如我的中间件是

  class Auth

    def initialize(app)
      @app = app
    end

    def call(env)
      @account ||= Account.find(1)

      @app.call(env)
    end
  end

上面的代码正确设置了@account 变量,但这在我的应用程序中不可用(在控制器、模型、视图......)。那么,我怎样才能做到这一点?


我看到this answer 这是一种满足我需要的方法,但我希望@account 变量“可直接访问”。也就是说,不使用那种方式,而是提供它,例如在我看来,像这样:

<%= debug @account %>

【问题讨论】:

  • 我不认为这可以在中间件中完成。您在ApplicationControllerbefore_filter :set_my_var 中尝试过吗?
  • @Wukerplank 我在中间件中需要它。
  • 您可以尝试一些肮脏且可能有害的东西,例如将其存储在Thread.current[:my_var] = Account.find(1)

标签: ruby-on-rails ruby ruby-on-rails-3 variables middleware


【解决方案1】:

您可以为此使用“env”。所以在你的中间件中你这样做:

def call(env)
  env['account'] = Account.find(1)
  @app.call(env)
end

您可以通过在您的应用中使用“请求”来获取价值:

request.env['account']

请不要像某些人在这里建议的那样使用全局变量或类属性。这肯定会让自己陷入麻烦,而且确实是个坏习惯。

【讨论】:

  • 感谢您的好回答。在您回答之后,我立即想起了omniauth,它使用了相同的做法。我还注意到你可以从路由约束中做同样的事情(在我的例子中,它对减少对数据库的请求数量特别有帮助)......你可以将任何值传递给 request.env 并在操作中捕获它或控制器。
【解决方案2】:

我不知道这是否可以通过 Middelware 完成。我的建议是这样的:

class ApplicationController < ActionController::Base

  protect_from_forgery

  before_filter :set_my_var

private
  def set_my_var
    @account ||= Account.find(1)
  end

end

这样你的所有控制器和视图都可以访问@account

【讨论】:

  • 这种方法的一个问题是当您在中间件本身计算某些东西以进行分配时。
【解决方案3】:

您可以在任何模型中使用 cattr_accessor :my_var 并通过中间件设置此变量

MyModel.my_var = '东西'

您可以在应用程序的任何位置访问它。

【讨论】:

  • 我没听懂。请你举个真实的例子好吗?
  • 在模型文件的某处添加“cattr_accessor :my_var”。这将为 MyModel.my_var 创建一个 setter 和 getter:pastie.org/2345283
  • 不是线程安全的,甚至不是主要问题的答案,如何将变量从中间件传递到控制器操作。
【解决方案4】:

您是否尝试过创建 Ruby 全局变量?

def call(env)
  $account ||= Account.find(1)

  @app.call(env)
end

<%= debug $account %>

【讨论】:

  • 在 100 种情况下,有 100 种情况下,全局变量不是答案。
猜你喜欢
  • 1970-01-01
  • 2019-12-22
  • 2018-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多