dimitarvp
dimitarvp

Reputation: 2383

How exactly do you use Rack's env hash?

I have a Rails 4.2 app with a heavy file upload traffic.

I want to override rack.multipart.tempfile_factory in order to provide additional behaviour associated with the temporary files Rack creates under the hood when accepting file uploads.

So where and how do I change Rack's env hash exactly? Tried doing env['...'] = ... inside an initializer, said env is undefined. Changing it to ENV raises an error saying it cannot convert a lambda to String (rack.multipart.tempfile_factory requires a lambda so I can't just change it to a String). Using request.env inside a controller method has no effect whatsoever. I tested the last by copy-pasting the stock Rack factory's one line of code and added writing a random number to a file with a fixed path; that file never got created in the first place after uploading a few files, so there you go.

I am looking for an official solution and don't have the intention to monkey-patch Rack. Its spec states this is possible, so how exactly should I be doing it?

Of course, if all else fails, I will resort to hacking, but I'd prefer to hear the official ways of doing it first.

(And while we're at this, can you also recommend a gemless solution to override rack.hijack_io, with some real-world examples? Searching for that thing in particular wasn't very helpful, nobody seems to provide an end-to-end working solution, only bits & pieces).

Thank you for your consideration.

Upvotes: 1

Views: 1256

Answers (1)

acsmith
acsmith

Reputation: 1496

Part 1: How to modify Rack's env

You just need to override Application#call. In config/application.rb (or config/environments/production.rb if you like) you add this method:

class Application < Rails::Application
  ...
  def call(env)
    env["rack.multipart.tempfile_factory"] = ->(what, now) { "lambda time" }
    super(env)
  end
  ...
end

See #call for more info on that.

Part 2: The meaning of ENV

ENV is a constant in Ruby that corresponds to the shell environment. This allows you to do things in your shell script like:

$ export MY_VAR=hahahaha
...
irb> ENV['MY_VAR'] #=> "hahahaha"

It's more than a Rack variable—it's a Ruby constant!

Your error "cannot convert lambda to string" is because all ENV values must be Strings. So even if you do

$ export MY_VAR=42

You'll get

irb> ENV['MY_VAR'] #=> "42"

where "42" is a String, not an Integer.

Upvotes: 2

Related Questions