rustrust-dieselrust-rockettera

How to display the value retrieved using Diesel in HTML using a Tera template in Rocket?


I want to display a value retrieved from the database with Diesel and serve it as HTML using a Tera template with Rocket:

#[get("/")]
fn index(db: DB) -> Template {
    use mlib::schema::users::dsl::*;
    let query = users.first::<User>(db.conn()).expect("Error loading users");
    let serialized = serde_json::to_string(&query).unwrap();
    println!("query = {:?}", &serialized);
    Template::render("index", &serialized)
}

The full sample code is here

It receives User { id: 1, name: "yamada" } from the database in #[get("/")] of src/main.rs and tries to render it with a template. It looks good to me, but this error is returned:

Error: Error rendering Tera template 'index': Failed to value_render 'index.html.tera': context isn't an object

Solution

  • The error message is telling you everything you need to know:

    context isn't an object
    

    And what is context? Check out the docs for Template::render:

    fn render<S, T>(name: S, context: &T) -> Template 
        where S: AsRef<str>,
              T: Serialize,
    

    This MCVE shows the problem:

    src/main.rs

    #![feature(plugin)]
    #![plugin(rocket_codegen)]
    
    extern crate rocket;
    extern crate rocket_contrib;
    
    use rocket_contrib::Template;
    
    #[get("/")]
    fn index() -> Template {
        let serialized = "hello".to_string();
        Template::render("index", &serialized)
    }
    
    fn main() {
        rocket::ignite().mount("/", routes![index]).launch();
    }
    

    Cargo.toml

    [dependencies]
    rocket = "0.1.6"
    rocket_codegen = "0.1.6"
    
    [dependencies.rocket_contrib]
    version = "0.1.6"
    features = ['tera_templates']
    

    templates/index.html.tera

    <html />
    

    Most templating engines work against a data structure that maps a name to a value. In many cases, this is something as simple as a HashMap, but Rocket allows you to pass in anything that can be serialized. This is intended to allow passing in a struct, but it also allows you to pass in things that do not map names to values, like a pure string.

    You have two choices:

    1. Create a HashMap (or maybe a BTreeMap) of values.
    2. Implement Serialize for a struct and pass that in.

    Here's the first option:

    use std::collections::HashMap;
    
    let mut serialized = HashMap::new();
    serialized.insert("greeting", "hello");
    Template::render("index", &serialized)