Applications with Mojolicious – Part Two: Routing and Templates

In the second post of the series we look into the bascic mechanisms of routing and rendering within Mojolicous and create the first requests of our app.

Mojolicious Series

Our first Route: Index

Let's define our first route. Open the lib/moblo.pm module.

In Mojolicious we create and manipulate routes using the router object $self->routes. Routes are mappings from incoming request URLs (or rather, patterns) to some entity returning a response.

The first route we create is to render an index page. (If you used the mojo generator from the last post, delete the route to example/welcome.)

1
2
3
4
5
6
7
8
9
10
11
sub startup {
    my $self = shift;

    # .. snip ..

    # Router
    my $r = $self->routes;

    # GET / -> Main::index()
    $r->get('/')->to(template => 'main/index');
}

As the index page doesn't require any additional data, we can directly render a template in the route definition. Compare this to the generated welcome route. It routed to the controller lib/moblo/Example.pm and the action welcome within. It called render with a stash variable named msg that was set from the controller.

To demonstrate the flexibility of routes, we can also change to route to use a controller to manually render data.

1
$r->get('/')->to('main#index');

This ties the returned content from the method index of the controller lib/moblo/Main.pm to the URL /. The Controller#action shortcut also has an equal alternative ->to(controller => 'Main', action => 'index'). Use whichever you prefer.

Let's create the controller counterpart. Create the controller file at lib/moblo/Main.pm. Every controller derives from the class Mojolicious::Controller. Mojolicious provides a shortcut for this definition through Mojo::Base. Thus, every controller module looks like this, with only the package defintion changing:

1
2
3
4
5
6
package Moblo::Main;
use Mojo::Base 'Mojolicious::Controller';

# Actions/Methods go here

1;

Now, the last and most important part is still missing: The action definition. Recall that actions are simply methods in the controller which return data to render.

In the generated welcome action, we already saw the render function to render a template with an additional variable stored in the stash.

1
2
3
4
sub index {
    my $self = shift;
    $self->render('main/index');
}

This action forces rendering the template templates/main/index and returns an error if it's missing.

By the way: Unless you manually render data yourself, Mojolicious will look for a template under templates/<controller>/<action> and use that automatically. Thus, the following action definitions are all equal within the controller Moblo::Main, given that the template file exists.

1
2
3
sub index {}
sub index { shift->render; }
sub index { shift->render('main/index'); }

The index template

So, now the request to / will return the content to the template templates/main/index. Let's bring it to life.

Mojolicious provides a templating engine ep for any kind of document.

Edit templates/main/index.html.ep.

1
2
3
4
<h2>Moblo &mdash; Blog Index</h2>
<p>Welcome to Moblo!</p>
<h3>Post Index</h3>
<p>None! :/</p>

Well, that's rather boring. Let's at least extend it with a link to a login page to gain access to the actual user management page.

Similar to Ruby's erb, the templating engine uses special tags <%= %>, %= for running and printing the output, as well as % and <% %> for running regular perl code within a template.

1
2
3
4
5
6
7
8
<h2>Moblo &mdash; Blog Index</h2>
<p>Welcome to Moblo!</p>
<h3>Post Index</h3>
<p>None! :/</p>
<hr>
<p>
    %= link_to Login => 'login_form'
</p>

Finally, templated code!

The used function link_to is a helper method that is exposed within the template file. Mojolicious provides a plethora of these helper functions to be used within the ep template engine (basically, you can execute any perl code within). The two built-in sets are DefaultHelpers, which provide access to internal data (stash, GET/POST data, etc.) and TagHelpers to create HTML tags. Later on, we will also create and use more advanced methods in the templates, such as content blocks, includes or form validation.

Layouts

You may have noticed that the above template is no complete HTML document. It's because I want to extract the outer body of the app into a separate file. With mojolicious, that's called a layout.

The layout is really just a special template which uses the helper method content, which is replaced with the rendered template file.

You can either set the layout manually in the call to $self->render like so:

1
$self->render('main/index', layout => 'base');

This will wrap the layout templates/layouts/base.html.ep around the contents of the index template. If you do not specify the layout, Mojolicious will try to use the default layout file located at templates/layouts/default.html.ep. By the way: You can override the default setting in your main application module (lib/moblo.pm in our case):

1
2
3
4
5
6
7
8
9
10
11
12
sub startup {
    my $self = shift;

     # Default layout
     $self->defaults(layout => 'base');

     # Router
     my $r = $self->routes;

     # ...

}

The layout file itself is just another template, which you can fill however you like. The following template shows the default layout for reference:

1
2
3
4
5
<!DOCTYPE html>
<html>
  <head><title><%= title %></title></head>
  <body><%= content %></body>
</html>

That's it for the introduction to routing and templates. In the next post, we will bring the login route to life.

Code at GitHub

You can browse the app at the state of this second post on Github.