如何从Rails中访问Rack环境?

Mic*_*ach 31 ruby rack middleware ruby-on-rails

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

class Foo
  def initialize(app)
    @app = app
  end
  def call(env)
    env["hello"] = "world"
    @app.call(env)
  end
end
Run Code Online (Sandbox Code Playgroud)

将我的Rack应用程序挂钩到Rails后,如何env["hello"]从Rails中获取访问权限?

更新:感谢Gaius的回答.Rack和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
Run Code Online (Sandbox Code Playgroud)

Jam*_*sen 27

我很确定你可以使用该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
Run Code Online (Sandbox Code Playgroud)

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

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

# controller:
def index
  if request.env['foo'] == 'bar'
    ...
  end
end
Run Code Online (Sandbox Code Playgroud)

  • (我知道它已经过时了)我相信第一个陈述不再正确(Rails 4+)。`Rack::Request.new(env)` 每次都会返回新对象,因此您无法在其中保留任何内容。[来源](https://github.com/rack/rack/blob/master/lib/rack/request.rb) (2认同)

Aje*_*i32 21

简答:使用request.envenv在控制器内部.

答案很长:

根据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不从Rack::Request,但ActionDispatch :: HTTP ::参数,它是由包括ActionDispatch::Request.此方法与该方法非常相似Rack::Request#params,只是更改它会修改特定于Rails的Rack环境变量(因此更改将在实例之间保持持久性ActionDispatch::Request).

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

总结一下:

在控制器......

  • 使用request.envenv获取原始环境对象
  • 使用params从机架上输入流中读取机架查询字符串和后数据.(例如Rack::Request#params)
  • 使用session访问的价值rack.session在机架环境

在中间件......

  • `env` 在 rails 5.0 ActionController https://github.com/rails/rails/commit/05934d24aff62d66fc62621aa38dae6456e276be 中已弃用 (3认同)