By default, each class will serve the path built from its underscored name.
Ex.: Forum
will serve "/forum", LatestNews
will serve "/latest_news" etc.
This can be changed by setting base URL via map
.
Example: - Book
app should serve "/books"
class Book < E
map '/books'
def index
# ...
end
def edit
# ...
end
end
Now `Book` will serve: /books - backed by Book#index /books/index - backed by Book#index /books/edit - backed by Book#edit
[ contents ↑ ]
Lets say you need your News
app to serve both "/news" and "/headlines" base URLs.
It is easily done by using map
with multiple params.
First param will be treated as base URL, any other consequent params - as canonical ones.
Example: - News
should serve both "/news" and "/headlines" paths.
class News < E
map :news, :headlines
def index
# ...
end
end
To find out either current URL is a canonical URL use canonical?
It will return nil
for base URLs and a string for canonial ones.
Example:
class App < E
map '/', '/cms'
def page
# on /page canonical? == nil
# on /cms/page canonical? == "/page"
end
# ...
end
[ contents ↑ ]
Defining Espresso actions is as simple as defining Ruby methods,
cause Espresso actions actually are pure Ruby methods.
Example: - Defining 2 actions - :index and :edit
class App < E
map '/'
def index
# ...
end
def edit
# ...
end
end
Now App
will serve:
- /
- /index
- /edit
[ contents ↑ ]
Usually actions should also contain non-alphanumeric chars.
Most common - hypes, dots and slashes.
To address this, Espresso uses a map to translate action names into HTTP paths.
The default map looks like this:
"____" => "." "___" => "-" "__" => "/"
Example:
def read____html # 4 underscores
# ...
end
# will serve read.html
def latest___news # 3 underscores
# ...
end
# will serve latest-news
def users__online # 2 underscores
# ...
end
# will serve users/online
Worth to note that you can define your own rules by using path_rule
at class level.
Example: - Convert bang methods into .html suffixed paths
class App < E
map '/'
path_rule "!", ".html"
def news!
# ...
end
end
# `news!` will serve /news.html
Example: - Convert methods starting with j_ into .json suffixed paths
class App < E
map '/'
path_rule /\Aj_/, ".json"
def j_news
# ...
end
end
# `j_news` will serve /news.json
[ contents ↑ ]
Espresso will split URL by slashes and feed obtained array to the Ruby method that backing current action.
Let's suppose we have an action like this:
class App < E
map '/'
def read type, status
# ...
end
end
If we do an request like this - "/read/news/latest", it will be decomposed as follow:
- action - read
- params - news/latest
Now Espresso will split params and call action:
read "news", "latest"
Current example will work just well, cause read
receives as many arguments as expected.
Now let's suppose we do an request like: "/read/news"
This wont work, cause read
receives 1 argument instead of 2 expected.
read "news"
And "/read/news/articles/latest" wont work either, cause read
receives too many arguments.
read "news", "articles", "latest"
However, as we know, Ruby is powerful enough.
And Espresso uses this power in full.
So, when we need read
method to accept 1 or 2 args,
we simply giving to last param a default value:
class App < E
map '/'
def read type, status = 'latest'
# ...
end
end
Now read
action will serve "/read/news" as well as
"/read/news/latest", "/read/news/archived", "/read/news/anything!"
Also we can make "/read/news/articles/latest" to work.
class App < E
map '/'
def read *types, status
# ...
end
end
That's it! Now when calling "/read/news/articles/latest",
types
will be an array like ["news", "articles"] and status will be equal to "latest".
In a word, if Ruby method works with given params, HTTP action will work too.
Otherwise, HTTP action will return "404 NotFound" error.
[ contents ↑ ]
format
allow to manipulate routing by instructing actions to respond to various extensions.
Example:
class App < E
map '/'
format :xml
def article
# ...
end
end
In the example above, article action will respond to both "/article" and "/article.xml" URLs.
format
accepts any number of arguments. Each argument is a new extension action(s) will respond to.
The second meaning of format
is to automatically set Content-Type header.
Content type are extracted from Rack::Mime::MIME_TYPES
map.
Ex: format :txt
will return the content type extracted via Rack::Mime::MIME_TYPES.fetch('.txt')
To set format(s) only for some actions, use setup
.
Example: - only :pages
and :news
actions will respond to URLs ending in .html and .xml
class App < E
map '/'
setup :pages, :news do
format :xml, :html
end
def read
# ...
end
def pages
# ...
end
def news
# ...
end
# ...
end
Voila, now App will respond to any of "/pages", "/pages.html", "/pages.xml", "/news", "/news.html", "/news.xml",
but not to "/read.html" nor to "/read.xml", cause format
was set for pages
and news
only.
But wait, actions usually are called with params, and an URL like "/read.html/100" looks really bad!
No problem! Espresso takes care about this, and "/read/100.html" will work exactly as "/read.html/100"
Even more! Espresso will get rid of format passed in last param, so you get clean params without remove format manually.
Meant that when "/news/100.html" requested, you get "100" param inside news
action, rather than "100.html"
Example:
class App < E
format :xml
def read item = nil
# on /read item == nil
# on /read.xml item == nil
# on /read.xml/book item == "book"
# on /read/book item == "book"
# on /read/book.xml item == "book"
# on /read/100.xml item == "100"
# on /read/blah.xml item == "blah"
# on /read/blah.json item == "blah.json"
end
end
Worth to Note - if both action and last param has format, action format is used.
Example:
class App < E
format :xml, :json
def read item = nil
# ...
end
end
/read/book.json will return JSON Content-Type /read.xml/book.json will return XML Content-Type instead
[ contents ↑ ]
By default, verbless actions will respond to any request method.
Example: - index
action responding to any request method
class App < E
def index
end
end
To make an action to respond only to a specific request method, simply prepend desired request method verb to action name.
Example:
class App < E
def post_news # will serve POST /news
# ...
end
def put_news # will serve PUT /news
# ...
end
# etc.
end
[ contents ↑ ]
As we already noted, any app can serve multiple paths.
But what if we need an action to be available by multiple paths?
It's easy - add an standard Ruby alias.
Example:
class App < E
map '/'
def news
# ...
end
alias news____html news
alias headlines__recent____html news
end
Now news
action will serve any of:
- /news
- /news.html
- /headlines/recent.html
[ contents ↑ ]
Espresso uses a really flexible rewrite engine, which allows to redirect the browser to new address as well as pass control to arbitrarry app(without redirect) or just send response to browser(without redirect as well).
A rewrite rule consist of regular expression and a block that receives matches as params.
redirect
and permanent_redirect
will redirect browser to new address with 302 and 301 codes respectivelly.
Example:
class App < E
rewrite /\A\/(.*)\.php\Z/ do |title|
redirect route(:index, title)
end
# ...
end
pass
will pass control to an arbitrary action or even app, without redirect.
Example:
class Articles < E
def read title
# ...
end
end
class Pages < E
# pass old pages to archive action
rewrite /\A\/(.*)\.php\Z/ do |title|
pass :archive, title
end
# pages ending in html are actually articles, so passing control to Articles app
rewrite /\A\/(.*)\.html\Z/ do |title|
pass Articles, :read, title
end
end
halt
will send response to browser and stop any code execution, without redirect.
It accepts from 0 to 3 arguments.
If argument is a hash, it is added to headers.
If argument is a Integer, it is treated as Status-Code.
Any other arguments are treated as body.
If a single argument given and it is an Array, it is treated as a bare Rack response and instantly sent to browser.
Example:
class App < E
rewrite /\A\/archived\/(.*)\.html\Z/ do |title|
page = Model::Page.first(:url => title) || halt(404, 'page not found')
halt page.content, 'Last-Modified' => page.last_modified.to_rfc2822
end
end
[ contents ↑ ]