35

我有一个看起来像这样的 Rack 应用程序:

class Foo
  def initialize(app)
    @app = app
  end
  def call(env)
    env["hello"] = "world"
    @app.call(env)
  end
end

将我的 Rack 应用程序连接到 Rails 后,如何env["hello"]从 Rails 中访问?

更新:感谢 Gaius 的回答。Rack and Rails 允许您在请求期间或会话期间存储内容:

# in middleware
def call(env)
  Rack::Request.new(env)["foo"] = "bar"  # sticks around for one request

  env["rack.session"] ||= {}
  env["rack.session"]["hello"] = "world" # sticks around for duration of session
end

# in Rails
def index
  if params["foo"] == "bar"
    ...
  end
  if session["hello"] == "world"
    ...
  end
end
4

2 回答 2

30

我很确定您可以使用该Rack::Request对象来传递请求范围变量:

# middleware:
def call(env)
  request = Rack::Request.new(env) # no matter how many times you do 'new' you always get the same object
  request[:foo] = 'bar'
  @app.call(env)
end

# Controller:
def index
  if params[:foo] == 'bar'
    ...
  end
end

或者,您可以直接获取该“ env”对象:

# middleware:
def call(env)
  env['foo'] = 'bar'
  @app.call(env)
end

# controller:
def index
  if request.env['foo'] == 'bar'
    ...
  end
end
于 2009-05-11T21:33:44.840 回答
27

简短回答:在控制器内部使用request.env或。env

长答案:

根据Rails 控制器上的 Rails 指南,ActionController 提供了一种request方法,您可以使用该方法来访问有关控制器正在响应的当前 HTTP 请求的信息。

在进一步检查文档后ActionController::Base#request,我们看到它“返回一个代表当前请求的 ActionDispatch::Request 实例”。

如果我们查看 的文档ActionDispatch::Request,我们会看到它继承自Rack::Request. 啊哈!开始了。

现在,如果您不熟悉 文档Rack::Request,它基本上是 Rack 环境的包装器。因此,在大多数情况下,您应该能够按原样使用它。如果你真的想要原始环境哈希,你可以用Rack::Request#env. 所以在 Rails 控制器中,这只是request.env.

深层发掘:

在进一步检查 的实例方法后ActionController::Base,我注意到那里没有太多可看的东西。特别是,我注意到paramssession变量似乎丢失了。所以,我上移了一级到ActionController::Metal,它ActionController::Base继承自。

ActionController::Metal中,我发现了一种方法env,它没有关于它的作用的文档——但我可以猜到。事实证明我是对的。该变量被分配给request.env.

ActionController::Metal还包含该params方法,根据来源,该方法默认设置为request.parameters。事实证明,request.parameters不是 from Rack::Request,而是ActionDispatch::Http::Parameters,它包含在ActionDispatch::Request. 该方法与该方法非常相似Rack::Request#params,不同之处在于更改它会修改特定于 Rails 的 Rack 环境变量(因此更改将在 的实例中保持不变ActionDispatch::Request)。

但是,我似乎仍然找不到session方法。事实证明,它根本不在文档中。在搜索了源代码后ActionController::Metal,我终于在这一行找到了它。没错,它只是request.session的一个快捷方式。

总结一下:

在控制器...

  • 使用request.envorenv获取原始环境对象
  • 用于params从机架输入流中读取机架查询字符串和发布数据。(例如Rack::Request#params
  • 用于session访问rack.session机架环境中的值

在中间件...

于 2014-05-29T17:34:02.800 回答