Search code examples
rustrust-rockethtml-templates

How to render attribute in Handlebars template from Rocket handler?


I am trying to render a template with Rust Rocket and Handlebars. This compiles but I can't get any arguments to the HTML file to work. The page loads, but the argument is not there. I am familiar with flask and jinja for Python but not as much with Rocket and Handlebars. I have tried countless things but I can't find any documentation that works.

#![feature(decl_macro)]

extern crate rocket;
extern crate rocket_contrib;

use rocket::{get, routes};
use rocket_contrib::templates::Template;

#[get("/one")]
fn one() -> String {
    format!("One")
}

#[get("/page")]
fn page() -> Template {
    let context = "string";
    Template::render("page", &context)
}

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

page.html.hbs

<!DOCTYPE html>
<head></head>
<html>
    <body>
        <h1>Argument is: {{context}}</h1>
    </body>
</html>

Solution

  • The template system doesn't know that the local variable is called context. It just knows that your context is a string, which doesn't have an attribute called context. You need to provide a type implementing Serialize, with a member called context for the template expression {{context}} to expand to anything. You could do this with a HashMap or a custom type.

    With a HashMap:

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

    With a custom type:

    #[get("/page")]
    fn page() -> Template {
        #[derive(serde_derive::Serialize)]
        struct PageContext {
            pub context: String,
        }
    
        let context = PageContext { context: "string" };
        Template::render("page", &context)
    }
    

    Custom types will generally perform better, and are self-documenting.