Reputation: 7594
I'm writing a small website in rust rocket. I'm using handlebar templates, and the way you return a Template
form a handler is quite convenient. But I also want to use my template engine for emails I'm sending out. The problem is, that Templates in rocket_contrib
do not really support rendering to a String
.
There is a method show()
, that creates Option<String>
, but that one is not supposed to be used.
Render the template named name located at the path root with the context context into a String. This method is very slow and should not be used in any running Rocket application. This method should only be used during testing to validate Template responses. For other uses, use
render
instead.
The method render()
is what you normally use, but this one returns a Template
, which is what I started with... You return those and rocket does its magic to produce the resulting html-page.
Is there any way to use my templates in rocket for emails? My mailer (lettre) expects a String.
Upvotes: 4
Views: 1110
Reputation: 15703
It's perfectly fine to use show()
. Here is how it's implemented in Rocket
:
pub fn show<S, C>(rocket: &Rocket, name: S, context: C) -> Option<String>
where S: Into<Cow<'static, str>>, C: Serialize
{
let ctxt = rocket.state::<ContextManager>().map(ContextManager::context).or_else(|| {
// N.B.: removed some logging for brevity
None
})?;
Template::render(name, context).finalize(&ctxt).ok().map(|v| v.0)
}
As you can see show()
does call render()
internally, just as the rustdoc told us to do instead. But here it also calls finalize()
. Let's check what does it do:
/// Actually render this template given a template context. This method is
/// called by the `Template` `Responder` implementation as well as
/// `Template::show()`.
Ok, so render()
does not really render anything. It's finalize()
that's doing the job.
We can also check how the Responder
is implemented:
/// Returns a response with the Content-Type derived from the template's
/// extension and a fixed-size body containing the rendered template. If
/// rendering fails, an `Err` of `Status::InternalServerError` is returned.
impl Responder<'static> for Template {
fn respond_to(self, req: &Request) -> response::Result<'static> {
let ctxt = req.guard::<State<ContextManager>>().succeeded().ok_or_else(|| {
// N.B.: removed some logging for brevity
Status::InternalServerError
})?.inner().context();
let (render, content_type) = self.finalize(&ctxt)?;
Content(content_type, render).respond_to(req)
}
}
TL;DR: It seems that the documentation is misleading. The template implementation is doing absolutely the same thing when you call show()
and when you send a response. In both cases it invokes finalize()
internally, which produces the String
rendering of the template. Thus there should not be any performance penalty of using show()
PS: The code in the current main
branch has changed a bit, but the logic is still the same
Upvotes: 2