Ruby on Rack #1 - Hello Rack!
Published over 4 years ago
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.
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 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 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
Let’s start with a smallest possible example of a rack application, using mongrel.
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 :
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 :
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 :
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.
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 :
# 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