Rails middlewares are small code pieces that wrap requests to the application. The first middleware gets passed the request, invokes the next, and so on. Finally, the application is invoked, builds a response and passes it back to the last middleware. Each middleware now returns the response until the request is answered. Think of it like Russian Dolls, where each middleware is a doll and the application is the innermost item.
You can run rake middleware
to get the ordered list of used middlewares in a Rails application:
$> rake middleware
use Webpacker::DevServerProxy
use Rack::Sendfile
use ActionDispatch::Static
use Rack::LiveReload
use ActionDispatch::Executor
use ActiveSupport::Cache::Strategy::LocalCache::Middleware
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use ActionDispatch::RemoteIp
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::DebugExceptions
use BetterErrors::Middleware
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
use Warden::Manager
use ExceptionNotification::Rack
use QueryDiet::Rack::ResetLogger
use OmniAuth::Strategies::SAML
run YourApp::Application.routes
This is helpful if you need to add or remove a middleware. Find more details in the docs for ActionDispatch::MiddlewareStack Show archive.org snapshot .
Since all middlewares run in each request, they must be very performant.
Example
Rails.application.configure do
config.middleware.insert_after ActionDispatch::ContentSecurityPolicy::Middleware, Demo::Middleware
end
module Demo
class Middleware
# `@app` is the next (inner) middleware in the stack, Rack::Head in this example
def initialize(app)
@app = app
end
# This middleware will be called by ActionDispatch::ContentSecurityPolicy::Middleware
def call(env)
# env may be modified here (request pre-processing)
# Here, the next middleware in the stack is invoked, passing in `env`.
# `@app.call` will return what it receives from Rack::Head.
status, headers, body = @app.call(env)
# status, headers and body may be modified before returning (request post-processing)
[status, headers, body]
end
end
end