Middleware
This guide gives an overview of the different Rack middleware used by Utopia.
Static
The class Utopia::Static
middleware services static files efficiently. By default, it works with Rack::Sendfile
and supports ETag
based caching. Normally, you'd prefer to put static files into public/_static
but it's also acceptable to put static content into pages/
if it makes sense.
use Utopia::Static,
# The root path to serve files from:
root: "path/to/root",
# The mime-types to recognize/serve:
types: [:default, :xiph],
# Cache-Control header for files:
cache_control: 'public, max-age=7200'
Redirection
The module Utopia::Redirection
middleware is used for redirecting requests based on patterns and status codes.
# String (fast hash lookup) rewriting:
use Utopia::Redirection::Rewrite,
'/' => '/welcome/index'
# Redirect directories (e.g. /) to an index file (e.g. /index):
use Utopia::Redirection::DirectoryIndex,
index: 'index.html'
# Redirect (error) status codes to actual pages:
use Utopia::Redirection::Errors,
404 => '/errors/file-not-found'
Localization
The class Utopia::Localization
middleware provides non-intrusive localization on top of the controller and view layers. The middleware uses the accept-language
header to guess the preferred locale out of the given options. If a request path maps to a resource, that resource is returned. Otherwise, a non-localized request is made.
use Utopia::Localization,
:default_locale => 'en',
:locales => ['en', 'de', 'ja', 'zh']
To localize a specific xnode
, append the locale as a postfix:
pages/index.xnode
pages/index.de.xnode
pages/index.ja.xnode
pages/index.zh.xnode
You can also access the current locale in the view via Utopia::Content::Node::Context#localization
.
Controller
The class Utopia::Controller
middleware provides flexible nested controllers with efficient behaviour. Controllers are nested in the pages
directory and are matched against the incoming request path recursively, from outer most to inner most.
use Utopia::Controller,
# The root directory where `controller.rb` files can be found.
root: 'path/to/root',
# The base class to use for all controllers:
base: Utopia::Controller::Base,
A controller is a file within the specified root directory (typically pages
) with the name controller.rb
. This code is dynamically loaded into an anonymous class and executed. The default controller has only a single function:
def passthrough(request, path)
# Call one of:
# This will cause the middleware to generate a response.
# def respond!(response)
# This will cause the controller to skip the request.
# def ignore!
# Request relative redirect. Respond with a redirect to the given target.
# def redirect! (target, status = 302)
# Controller relative redirect.
# def goto!(target, status = 302)
# Respond with an error which indiciates some kind of failure.
# def fail!(error = 400, message = nil)
# Succeed the request and immediately respond.
# def succeed!(status: 200, headers: {}, **options)
# options may include content: string or body: Enumerable (as per Rack specifications
end
The controller layer can do more complex operations by prepending modules into it.
prepend Rewrite, Actions
# Extracts an Integer
rewrite.extract_prefix id: Integer do
@user = User.find_by_id(@id)
end
on 'edit' do |request, path|
if request.post?
@user.update_attributes(request[:user])
end
end
otherwise do |request, path|
# Executed if no specific named actions were executed.
succeed!
end
The incoming path is relative to the path of the controller itself.
Content
The class Utopia::Content
middleware parses XML-style templates with using attributes provided by the controller layer. Dynamic tags can be used to build modular content.
use Utopia::Content
A basic template create.xnode
looks something like:
<content:page>
<content:heading>Create User</content:heading>
<form action="#">
<input name="name" />
<input type="submit" />
</form>
</content:page>
This template would typically be designed with supporting _page.xnode
and _heading.xnode
in the same directory or, more typically, somewhere further up the directory hierarchy.
Session
The class Utopia::Session
middleware provides session storage using encrypted client-side cookies. The session management uses symmetric private key encryption to store data on the client and avoid tampering.
use Utopia::Session,
expires_after: 3600 * 24,
# The private key is retried from the `environment.yaml` file:
secret: UTOPIA.secret_for(:session),
secure: true
All session data is stored on the client, but it's encrypted with a salt and the secret key. It is impossible for the client to decrypt the data without the secret stored on the server.