What is Rack? A Ruby on Rails Webserver Interface
As a Ruby on Rails developer at SoluteLabs, when I came across Rack application in one of our projects it encouraged me to dig deeper into insides of Rack and helped me to find the answers of below questions,
- What is the Rack application?
- What is Rack middleware?
- Where it is used?
What is Rack?
As per Rack, it provides a minimal interface between web servers that support Ruby and Ruby frameworks.
In simple terms, Rack sits between the ruby based application and web server helping them to interact with each other.
Creating Rack application
Rack application is nothing but the object that responds to the call method.
To run our newly created application invoke rackup config.ru command. Now go to http://localhost:9292/ and our application will be available there.
When we hit the above URL, in server run command will be invoked and it will call method call on Hello.new object.
If you look at the call method, it accepts the environment hash which contains information about the incoming HTTP request and the environment in which application is running as an argument and returns an array of exactly three values: The status, headers, and body.
Now let’s take look at few of Rack’s terms:
run
It takes Ruby object which responds to method call as an argument and runs call method on it.
map
It takes a string as a parameter and maps incoming requests against it and if it matches it will run the block assign to handle that.
Use
It includes the middleware in rack application.
What is Rack Middleware?
Middleware
You can refer rack middleware as a small component that assists with the execution of a task. For example, You can think of different middleware doing different processes like logging, caching.
It can modify or halt requests before they reach the final middleware(The object which we assigned to run method).
Middleware Stack
When you include more than one middleware it is called middleware stack. Its implementation is similar to pipeline design pattern for a web server that uses Rack. It means every incoming request passes through each middleware in the same order as they are defined.
Built-in middlewares
There are many already built-in middleware components in rack available to use in your Rack application.
Creating custom Middleware and using it in Rack Application
Let’s create our own custom middleware Cookie which will add cookies to response.
First, starting from constructor you may have noticed the app parameter in it. The app is next application middleware and every middleware constructor must have to include it.
This middleware calls @app.call(call) first which will call the next middleware in the stack(In our case it is Hello) and return its response. After that Cookie middleware will add cookies to respond and return the response back to the application.
As explained above use command is used for adding middleware in the stack, we can use Cookies middleware in our Rack application as above.
Rails and Rack
If rails project directory if you run rake middleware it will give the list of middlewares being used in rails as below,
use Rack::Sendfile
use ActionDispatch::Static
use ActionDispatch::Executor
use ActiveSupport::Cache::Strategy::LocalCache::Middleware
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use ActionDispatch::RemoteIp
use Sprockets::Rails::QuietAssets
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use WebConsole::Middleware
use ActionDispatch::DebugExceptions
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ContentSecurityPolicy::Middleware
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Rack::TempfileReaper
run RailsRakeDemoApp::Application.routes
Every incoming request to your app will pass through this stack from up to bottom and finally giving its control to routes which dispatch request to the controller, controller process it and returns the response. This response will again pass through this middleware stack from bottom to up.
But how these middlewares are being invoked and where they are defined?
Every Ruby on Rails project have a config.ru file in its root directory and it has following content,
This file loads config/environment files and invokes Rails.application which will call Application defined in application.rb.
Now let’s look at what does application.rb have,
Here Application is inherited from Rails::Application which is inherited from Engine. This Engine is a Rack application that has a call method defined in it which is being invoked when config.ru calls Rails.application. This is how Ruby on Rails application uses Rack.
Rails::Application class loads DefaultMiddlewareStack which have the same middleware stack defined in it which we went through earlier.
How can I use it?
Rails allow you to configure middleware stack for adding your custom middleware to stack, deleting middleware from the stack and, changing the position of any middleware from the stack.