How do I access the Rack environment from within Rails? How do I access the Rack environment from within Rails? ruby ruby

How do I access the Rack environment from within Rails?


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

# 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'    ...  endend

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

# middleware:def call(env)  env['foo'] = 'bar'  @app.call(env)end# controller:def index  if request.env['foo'] == 'bar'    ...  endend


Short answer: Use request.env or env inside a controller.

Long answer:

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

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

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

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.

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 params and session variables seem to be missing. So, I moved up one level to ActionController::Metal, which ActionController::Base inherits from.

In ActionController::Metal, I discovered a method env which 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 also contained the params method, which, according to the source, was set to request.parameters by default. As it turns out, request.parameters isn't from Rack::Request, but ActionDispatch::Http::Parameters, which is included by ActionDispatch::Request. This method is very similar to the Rack::Request#params method, except that altering it modifies a Rails-specific Rack environment variable (and therefore changes will remain persistent across instances of ActionDispatch::Request).

However, I still couldn't seem to find the session method. 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.

To summarize:

In the controller...

  • Use request.env or env to get at the raw environment object
  • Use params to read Rack query strings and post data from the rack input stream. (E.g. Rack::Request#params)
  • Use session to access the value of rack.session in the rack environment

In the middleware...