A blog with the web framework Rocket - part 2

A home page for our blog

Tera installation

We will use the template engine tera.

In the Cargo file

First, we register it in the Cargo file:

[package]
name = "blog-rs"
version = "0.1.0"
authors = [" my_user_name <my_mail>"]
edition = "2018"

[dependencies]
rocket = "0.4.0"

[dependencies.rocket_contrib]
version = "*"
default-features = false
features = ["tera_templates"]

Preparation of the rocket

Then in our src/main.rs, we import rocket_contrib::templates::Template;:

#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use]
extern crate rocket;
extern crate rocket_contrib;

use rocket_contrib::templates::Template;

// ...

Preparation of our rocket

Then we create our route to the home page:

// ...

use rocket_contrib::templates::Template;

// We use HashMap to pass a context to our templates use
std::collections::HashMap;

#[get("/")]
fn home() -> Template {
    // We create our context, passing in it a title variable
    // containing the string slice "Welcome"
    let mut context = HashMap::new();
    context.insert("title", "Welcome");
    // Then we render our template.
    Template::render("home", &context)
}

Then we mount our route and attach the method Template::fairing() to the rocket:

fn main() {
    rocket::ignite()
    .mount("/", routes![home])
    .attach(Template::fairing())
    .launch();
}

Alright, our rocket is almost ready to be launched!

Creation of our templates

A base template

We create a base template that we extends for every template we will render. We place all our templates in the templates/ directory.

Here is our base template:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Our blog app - {% block title %}{% endblock %}</title>
</head>
<body>
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="">A link to log in, not ready yet</a></li>
  </ul>
  {% block content %}
  {% endblock %}
</body>
</html>

And our home template:

{% extends "base" %}

{% block title %}{{ title }}{% endblock %}

{% block content %}
<h1>Welcome on our blog application!!!</h1>
{% endblock %}

Now you can launch the rocket:

cargo run

Add some style

To style our application, we will use materializecss (any other solution, is OK, it is up to you). We won't use CDN to use materialize. So let's create a static directory at the root of our application and 3 subdirectories: static/js, static/css and static/fonts. In the directory static/fonts, place the Roboto fonts that you can download at https://fonts.google.com/

Then our project is organized like this:

Custom the rocket

We use a static_path variable as rocket mount point will change the relative path of the css files downloaded. We must pass this variable to the template in our home function:

#[get("/")]
fn home() -> Template {
    let mut context = HashMap::new();
    context.insert("title", "Welcome");
    context.insert("static_path", "");
    Template::render("home", &context)
}

Then we must also mount our static files, then we use the StaticFiles custom handler from rocket_contrib:

First, we register it into Cargo.toml:

# ..
[dependencies.rocket_contrib]
version = "*"
default-features = false
features = ["tera_templates", "serve"]

We mount our static files on /public, as they are accessible to everyone. Static files must be mount first, otherwise it is not working, yet I don't know why.

// ...
use rocket_contrib::serve::StaticFiles;
// ..
fn main() {
    rocket::ignite()
        .mount("/public", StaticFiles::from("/static"))
        .mount("/", routes![home])
        .attach(Template::fairing())
        .launch();
}

Now in our base template we import css and js files:

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
  <title>Our blog app - {% block title %}{% endblock %}</title>
  <link rel="stylesheet" href="{{ static_path }}/public/css/materialize.css">
</head>
<body>
  // ..
  <div class="container">
    {% block content %}
    {% endblock %}
  </div>
  <script type="text/javascript" src="{{ static_path }}/public/js/materialize.js"></script>
</body>
</html>

And to finish this part we add a simple navigation bar to our app. This navbar will be usefull for a user to log into the application and once she is logged in, she could see her articles she wrote. So we just modify the base template.

<!-- .. -->
<body>
  <nav class="navbar navbar-default teal">
    <div class="container">
      <div class="nav-wrapper">
        <a href="/">Our blog</a>
        <ul class="right hide-on-med-and-down">
          <li><a href="">Login</a></li>
        </ul>
      </div>
    </div>
  </nav>
<!-- .. -->