Imagine you want to add a new middleware for your application that does a simple thing: verify a token sent in the header by the client code. If this token matches our secret token, allow the request to proceed. Otherwise, immediately return an error without passing the request to the application.

To accomplish this, let's introduce a custom middleware, which is just a Ruby class with the interface we saw in the introduction. As mentioned above, it will have a call method that takes the incoming request and returns an array containing the HTTP status, headers, and the response body.

# lib/middleware/verify_token.rb

module Middleware
  class VerifyToken
    def initialize(app)
      @app = app
    end

    def call(env)
      request = ActionDispatch::Request.new(env)
      if request.headers['token'] != 'my-secret-token'
        return [200, {}, ['invalid or missing token']]
      end

      @app.call(env)
    end
  end
end

As you can see, in the call method, we'll first verify the token and return an error if it doesn't match our secret token. If it matches, we send the normal response.

Where do you put middleware in your Rails app?

Middleware can't be in app because they can't be reloaded. They should be in lib. - Rafael Franca

Let's create a new folder called middleware in the lib folder and add VerifyToken middleware in it.

We're not done yet, we need to tell Rails to insert this middleware in the middleware stack. Let's do this using the config.middleware object.

Rails Middleware API

Rails provides a simple configuration interface config.middleware for adding, removing, and modifying the middleware stack.

The object returned by config.middleware method is an instance of Rails::Configuration::MiddlewareStackProxy class. As the name suggests, it's a proxy for the Rails middleware stack that lets you configure the middleware for your application.

You can either use config.middleware in the application.rb file or one of the environment-specific configuration files under the environments/<env>.rb file.

To add a new middleware, use the config.middleware.use method, passing the name of the Ruby class that acts as middleware. Rails will insert this middleware at the end of the existing middleware stack, meaning it will get executed in the end, just before your application is called.

# config/application.rb

require_relative "../lib/middleware/verify_token"

module Blog
  class Application < Rails::Application
    config.middleware.use Middleware::VerifyToken
  end
end

That's it! We've successfully added a middleware to verify an incoming request.

Instead of putting your middleware in the end, if you wish to insert it before or after another middleware, you can do so using the insert_before or insert_after method.

config.middleware.insert_before ActionDispatch::Callbacks, VerifyToken

This will insert the VerifyToken callback before the ActionDispatch::Callbacks middleware runs.