Ruby-on-rails 如何从 Rails 中访问 Rack 环境?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/848591/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:14:19  来源:igfitidea点击:

How do I access the Rack environment from within Rails?

ruby-on-railsrubyrackmiddleware

提问by Michael Gundlach

I have a Rack application that looks like this:

我有一个如下所示的 Rack 应用程序:

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

After hooking my Rack application into Rails, how do I get access to env["hello"]from within Rails?

将 Rack 应用程序挂接到 Rails 后,如何env["hello"]从 Rails 内部访问?

Update: Thanks to Gaius for the answer. Rack and Rails let you store things for the duration of the request, or the duration of the session:

更新:感谢 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

采纳答案by James A. Rosen

I'm pretty sure you can use the Rack::Requestobject for passing request-scope variables:

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

Alternatively, you can get at that "env" object directly:

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

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

# controller:
def index
  if request.env['foo'] == 'bar'
    ...
  end
end

回答by Ajedi32

Short answer:Use request.envor envinside a controller.

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

Long answer:

长答案:

According to the Rails Guide on Rails controllers, ActionController provides a requestmethod that you can use to access information about the current HTTP request your controller is responding to.

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

Upon further inspection of the docs for ActionController::Base#request, we see that it "Returns an ActionDispatch::Request instance that represents the current request."

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

If we look at the docs for ActionDispatch::Request, we see that it inherits from Rack::Request. Aha! Here we go.

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

Now, in case you're not familiar with the docs for Rack::Request, it's basically a wrapper around the Rack environment. So for most cases, you should just be able to use it as-is. If you really do want the raw environment hash though, you can get it with Rack::Request#env. So within the Rails controller, that would just be request.env.

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

Digging deeper:

深层发掘:

After further examining the instance methods of ActionController::Base, I noticed there's not a whole lot there to look at. In particular, I noticed the paramsand sessionvariables seem to be missing. So, I moved up one level to ActionController::Metal, which ActionController::Baseinherits from.

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

In ActionController::Metal, I discovered a method envwhich had no documentation as to what it did - but I could guess. Turns out I was right. That variable was being assigned to request.env.

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

ActionController::Metalalso contained the paramsmethod, which, according to the source, was set to request.parametersby default. As it turns out, request.parametersisn't from Rack::Request, but ActionDispatch::Http::Parameters, which is included by ActionDispatch::Request. This method is very similar to the Rack::Request#paramsmethod, except that altering it modifies a Rails-specific Rack environment variable (and therefore changes will remain persistent across instances of ActionDispatch::Request).

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

However, I still couldn't seem to find the sessionmethod. Turns out, it's not in the documentation at all. After searching the source code for ActionController::Metal, I finally found it on this line. That's right, it's just a shortcut for request.session.

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

To summarize:

总结一下:

In the controller...

在控制器...

  • Use request.envor envto get at the raw environment object
  • Use paramsto read Rack query strings and post data from the rack input stream. (E.g. Rack::Request#params)
  • Use sessionto access the value of rack.sessionin the rack environment
  • 使用request.envenv获取原始环境对象
  • 使用params读取从机架输入流机架查询字符串和后数据。(例如Rack::Request#params
  • 使用session访问的价值rack.session在机架环境

In the middleware...

在中间件...