Ruby community is coming up with new frameworks almost every week, but in midst of that, Rack isn’t getting enough attention. Attention that it deserves. And also, the next stable release of Rails after 2.2 will have a better public facing interface for taking full advantage of Rack.
Rack was initially inspired from pythons’s wsgi and it quickly became the de-facto web application/server interface in the ruby community, thanks to it’s simplicity and preciseness. You might want to read Introducing Rack from the creator of rack – Christian Neukirchen before reading this post.
What is Rack ?
Rack provides a minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call.
Practically speaking, you can divide “Rack” in two parts :
Rack Specification
Rack specification specifies how exactly a Rack application and the web server should communicate :
A Rack application is an Ruby object (not a class) that responds to call. It takes exactly one argument, the environment and returns an Array of exactly three values: The status, the headers, and the body.
That’s the specification in a nutshell. You can check out the full details here.
Strictly speaking, you don’t need the rack gem in order to write Rack ready applications. Just stick to the specification and that’s it.
Rack Gem
Rack gem is a collection of utilities and facilitating classes, to make life easier for anyone developing Rack applications. It includes basic implementations of request, response, cookies & sessions. And a good number of usefult middlewares. In short, install the rack gem. You’re gonna need it :
$ sudo gem install rack
To summarize
- Rack is a framework to roll your own ruby framework.
- Rack provides an interface between different web servers and your framework/application. Making it very simple for your framework/application to be compatible with any webserver that supports Rack – Phusion Passenger, Litespeed, Mongrel, Thin, Ebb, Webrick to name a few.
- Rack cuts your chase. You get request, response, cookies, params & sessions for free.
- Makes it possible to use multiple frameworks for the same application, provided there is no class collision. Rails and sinatra integration is a good example of this.
- Middlewares ! Think of middlewares as Rails’s before_filter/after_filter that are reusable across different rack supported frameworks/applications. For example, you can use the same Anti-spamming rack middleware for your Rails app, Sinatra app and your custom Rack application too!
Examples
Let’s start with a smallest possible example of a rack application, using mongrel.
1 2 3 4 5 6 7 8 9 10 |
require 'rubygems' require 'rack' class HelloWorld def call(env) [200, {"Content-Type" => "text/html"}, "Hello Rack!"] end end Rack::Handler::Mongrel.run HelloWorld.new, :Port => 9292 |
The above code passes an object of HelloWorld to the mongrel rack handler, and starts the server on port 9292.
The HelloWorld object here respects the rack specifications. That is :- Responds to call(), which takes one argument – environment
- call() returns an Array of [http_status_code, response_headers_hash, body]
That’s all ! If you run this script and browse to http://localhost:9292, you’ll see the shiny “Hello Rack!” message.
But hey, even a ruby proc responds to call(). So why not use a proc instead ? Well, no reason not to :
1 2 3 4 |
require 'rubygems' require 'rack' Rack::Handler::Mongrel.run proc {|env| [200, {"Content-Type" => "text/html"}, "Hello Rack!"]}, :Port => 9292 |
Another common seen pattern is to use method(:something), which returns an object of Method class :
1 2 3 4 5 6 7 8 |
require 'rubygems' require 'rack' def application(env) [200, {"Content-Type" => "text/html"}, "Hello Rack!"] end Rack::Handler::Mongrel.run method(:application), :Port => 9292 |
Take that you “Hello World” performance retards. You’re not gonna be able to write a faster ‘Hello World’ ruby application than this.
Rack it up’
As I said earlier, rack gem comes with a bunch of useful stuff to make life easier of a rack application developer. rackup is one of them. In the previous examples, I had used the mongrel handler Rack::Handler::Mongrel directly, and even hard coded the port number. With rackup, these things become configurable ! But to use rackup, you’ll need to supply it with a rackup config file. For our above example, the config file will look somewhat like :
1 2 |
# config.ru run Proc.new {|env| [200, {"Content-Type" => "text/html"}, "Hello Rack!"]} |
Just a line. By convention, you should use .ru extension for a rackup config file. Supply it a run RackObject and you’re ready to go :
$ rackup config.ru
By default, rackup will start a server on port 9292. But you can override that with a -p option to rackup. For more help, RTFM:
$ rackup --help





Nice article, this has cleared a few things up about rack for me!
I’ve been looking into comet solutions, and I would love a native Ruby/Rack solution. Any speculation on what might happen when call and or body.each take a long time to return a value?
Would event basted client handle this properly?
Nice introduction to Rack! I agree it is not getting the attention I think it deserves. I wrote a blog post on creating a simple piece of rack middleware where I try to show how simple it is to create your own (http://www.decodeuri.com/2008/10/15/creating-a-rack-middleware-for-minifying-your-javascript-files/). It’d be great to know your (and everybody else’s) thoughts about it :)
Very nice. I’ve enjoyed your Rails + Sinatra articles along a similar vein.
I’m looking forward to future editions of Rails for improved Rack support. Right now I’m leaning towards redirecting requests via nginx config between Rack frameworks like Sinatra as opposed to Rack cascade although the ease of sharing models, etc. as you highlighted in the previous post make the future of combining frameworks very appealing.
very nice.
i translated it into Chinese! http://www.yeeyan.com/articles/view/blackanger/18184
‘Take that you “Hello World” performance retards’ lol