如何修复Rocket框架中Handlebars模板的‘Helper not defined’错误?
修复Rocket v0.5 + Handlebars模板渲染的"Helper not defined: Path(Relative(([Named("parent")]), "parent"))"错误
问题背景
访问网站时出现以下错误:
>> Matched: (index) GET / >> Handlebars: Error rendering "index" line 9, col 1: Helper not defined: Path(Relative(([Named("parent")]), "parent")) >> Template 'index' failed to render. >> Outcome: Failure >> No 500 catcher registered. Using Rocket default. >> Response succeeded.
对应的代码与模板文件如下:
Rust代码
#[macro_use] extern crate rocket; use rocket::Request; use rocket_dyn_templates::Template; #[derive(serde::Serialize)] struct BoardContext { parent: &'static str, } #[derive(serde::Serialize)] struct AboutContext { parent: &'static str, } #[derive(serde::Serialize)] struct LegalsContext { parent: &'static str, } #[derive(serde::Serialize)] struct NotFoundContext { parent: &'static str, url: String, } #[get("/")] fn index() -> Template { Template::render("index", &BoardContext { parent: "layout" }) } #[get("/about")] fn about() -> Template { Template::render("about", &AboutContext { parent: "layout" }) } #[get("/legals")] fn legals() -> Template { Template::render("legals", &AboutContext { parent: "layout" }) } #[catch(404)] fn not_found(req: &Request) -> Template { Template::render( "not_found", NotFoundContext { parent: "layout", url: req.uri().to_string(), }, ) } #[launch] fn rocket() -> _ { rocket::build() .register("/", catchers![not_found]) .mount("/", routes![index, about, legals]) .attach(Template::fairing()) }
index.html.hbs
{{#*inline "page"}} <section id="message_board"> <h1>Hi, there!</h1> Welcome to my meaningless Website! </section> {{/inline}} {{~> (parent)~}}
layout.html.hbs
<!doctype html> <html> <head> <title>website</title> </head> <body> {{> header}} {{~> page}} {{> footer}} </body> </html>
问题根源
你试图通过{{~> (parent)~}}直接引用上下文中的parent变量作为模板名称,但Handlebars默认不支持这种直接的路径解析写法,必须借助lookup helper从当前上下文获取变量值,再将其作为模板名称传递。
修复方案
1. 修改模板的动态引用写法
将index.html.hbs中的{{~> (parent)~}}替换为:
{{~> (lookup . "parent")~}}
lookup helper会从当前上下文(.代表当前上下文)中取出parent字段的值(即"layout"),然后将其作为模板名称加载layout.html.hbs,这是Handlebars动态引用模板的标准写法。
2. 验证模板文件位置
确保所有模板文件(layout.html.hbs、index.html.hbs、header.html.hbs、footer.html.hbs等)都放在Rocket默认的templates/目录下,目录结构应为:
your_project/ ├── src/ │ └── main.rs └── templates/ ├── layout.html.hbs ├── index.html.hbs ├── about.html.hbs ├── legals.html.hbs ├── not_found.html.hbs ├── header.html.hbs └── footer.html.hbs
3. 优化上下文结构体(可选)
当前定义了多个重复的上下文结构体,可以合并为一个通用结构体减少冗余:
#[derive(serde::Serialize)] struct PageContext { parent: &'static str, url: Option<String>, }
对应修改各个handler:
#[get("/")] fn index() -> Template { Template::render("index", &PageContext { parent: "layout", url: None }) } #[get("/about")] fn about() -> Template { Template::render("about", &PageContext { parent: "layout", url: None }) } #[get("/legals")] fn legals() -> Template { Template::render("legals", &PageContext { parent: "layout", url: None }) } #[catch(404)] fn not_found(req: &Request) -> Template { Template::render( "not_found", PageContext { parent: "layout", url: Some(req.uri().to_string()), }, ) }
验证修复效果
修改完成后重新编译运行项目,访问网站即可正常渲染页面,错误会被解决。
内容的提问来源于stack exchange,提问作者nilch
相关产品推荐
相关产品推荐

