我有一个 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 内部?

更新:感谢盖乌斯的回答。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
有帮助吗?

解决方案

我很确定你可以使用 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

其他提示

简短回答: 使用 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 不是来自 Rack::Request, , 但 ActionDispatch::Http::参数, ,它包含在 ActionDispatch::Request. 。这个方法非常类似于 Rack::Request#params 方法,除了改变它会修改 Rails 特定的 Rack 环境变量(因此更改将在 ActionDispatch::Request).

然而我似乎还是没能找到 session 方法。事实证明,它根本不在文档中。搜索源码后 ActionController::Metal, ,我终于找到了 这条线. 。没错,这只是一个捷径 请求会话.

总结一下:

在控制器中...

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

在中间件...

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top