Ruby & Ruby On Rails Interview Preparation- Part 2(Rack)

Ruby Devs
Ruby Devs
Sep 5, 2018 · 3 min read

Rack is another important topic, which you should not be ignoring while preparing or while understanding Rails or are trying to build a ruby application. Now what is Rack? Where is it used? How do we develop rack application? How does Rack works?

All the above mentioned things will be covered. But first let us understand 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.

So for example when you are requesting for a particular webpage on any website, the request is sent to web server (e.g, apache, nginx), which it sends to the application server(i.e. puma, thin, unicorn), now when the application server has your request, it sends it to the rack which actually talks to your rails application. So there are 4 things we have touched here:

  1. Web Server — Takes request from user and do some processing and may or may not give it to Rails application. For e.g. js, css or images doesn’t change often, so it sends it without sending the request to application, that is the place where it is like very fast. But if the request does need to go our application, it is sent via an app server or application server
  2. App server — Server actually running the rails app, when it gets a request from web server it lets the application know, however not directly but via a rack. In development environment, we usually have only an app server running and not a web server.
  3. Rack — common language that Ruby web frameworks (like Rails) and app servers both speak
  4. Rails Application

So now you know where the rack actually fits in the request handling and response handling.

Now lets see the rack interface:

To use Rack, provide an “app”: an object that responds to the call method, taking the environment hash as a parameter, and returning an Array with three elements:

  • The HTTP response code
  • A Hash of headers
  • The response body, which must respond to each
1. require 'rack'2. app = Proc.new do |env|3. ['200', {'Content-Type' => 'text/html'}, ['A barebones rack app.']]4. end5. Rack::Handler::WEBrick.run app

In first line we are requiring the rack library, the next line we are defining a proc, since it responds to call, and takes the env as a parameter and then returns in line 3 three things [HTTP response code, Hash of Headers, Response Body], and lastly we have used WEBrick to run our app. We could have used lambda as well,

 require 'rack' app = -> (env) do |env| ['200', {'Content-Type' => 'text/html'}, ['A barebones rack app.']] end Rack::Handler::WEBrick.run app

We also hear a lot about the Middleware, but what exactly is a middleware.

Middleware are the building blocks of larger applications built using the Rack pattern. Each middleware is a Rack compatible application, and our final application is built by composing together, or nesting these middleware.

Lets build a simple logging middleware rack compliant application

require 'rack'app = -> (env) do |env|['200', {'Content-Type' => 'text/html'}, ['A barebones rack app.']]end
class LoggingMiddleware
def initialize(app)
@app = app
end
def call(env)
before = Time.now.to_i
status, headers, body = @app.call(env)
after = Time.now.to_i
log_message = "App took #{after - before} seconds."
[status, headers, body << log_message]
end
end
Rack::Handler::WEBrick.run LoggingMiddleware.new(app)

Here also, LoggingMiddleware is rack compliant, since it’s object responds to the call method, taking the environment hash as a parameter, and returning an Array with three elements.

Say we have 5 middle wares in our app, then it becomes quite verbose, rack provides an easier way of doing it, just define a config.ru (ru stands for rackup file), which automatically loads the middlewares.

#save this in a config.ru file
use FirstMiddleware
use SecondMiddleware
use LoggingMiddleware
run OurApp.new

Once we have a config.ru to structure our middleware stack, we can run the resulting Rack application using the bare rackup command, provided by the rack gem. By running through rackup, rack will automatically be required and the DSL of the use and run methods will be exposed

Rack::Builder provides use and run methods, and makes it easier for us to add or remove middleware.

Written by

Ruby Devs

The things we encounter daily as rubyists and sometimes while switching jobs :p

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade