Closed tecywiz121 closed 3 years ago
This crate is where I'd like to be able to add some additional templates for a login and a logout page.
Can you before more specific about what you're calling a "module" here and point me to where in your code these modules are defined as well as where the separate templates live?
If you're launching multiple instances of Rocket
, at present, you'll need to build a Config
with an appropriate template_dir
extra
for each instance, or use a different Rocket.toml
file, or supply the template_dir
via the ROCKET_TEMPLATE_DIR
environment variable.
Sure thing! I've moved things around a little bit to make it more clear. Everything is on the auth
branch for now.
The "core" application is called bellhop, and lives here.
I'm doing some refactoring to support different types of authentication. I've moved some routes from the bellhop
crate into another crate called bellhop-auth-dummy
, and you can see those routes here.
I'm having trouble figuring out how to move the templates from here into the bellhop-auth-dummy
crate.
@tecywiz121 I'm sorry, but I'm still not sure if I totally understand. Here's what I've grokked thus far:
bellhop
at ./bellhop
.bellhop-auth-dummy
in ./bellhop-auth-dummy
.bellhop
in ./bellhop/templates
.bellhop-auth-dummy
in ./bellhop/templates/login
.Is that the correct lay of the land?
If so, then the answer to your question depends on which templates, if any, are shared by bellhop
and bellhop-auth-dummy
. If none, then simply move the login
templates to the bellhop-auth-dummy
directory and either crate a new Rocket.toml
or override the template configuration parameter when running the application via a ROCKET_TEMPLATE_DIR=path/to/bellhop-auth-dummy/templates
environment variable.
If they are sharing templates, then you can simple use the same template_dir
for both and use the proper path in each case, which appears to be what you're doing.
No worries, I'm probably explaining myself poorly. I'm coming from a django background, so I'm probably taking a lot for granted. I really appreciate you taking the time to respond!
- You have one Rocket application in the crate
bellhop
at./bellhop
.
I have most of a single Rocket application at ./bellhop
, but that crate is a library. The main.rs
is over in bellhop-bin
.
The intended design is to be able to compose together bellhop
with different authentication plugins (like bellhop-auth-dummy
) into a single binary.
- You have a second, distinct Rocket application
bellhop-auth-dummy
in./bellhop-auth-dummy
.
I wouldn't call it a "distinct" Rocket application. It's probably closer to a fairing. In fact, it probably should be a fairing now that I think about it.
bellhop-auth-dummy
is like a plugin that provides one flavor of authentication for bellhop
.
- You have templates for
bellhop
in./bellhop/templates
.
Correct.
- You have templates for
bellhop-auth-dummy
in./bellhop/templates/login
.
Yes, but I don't want them there anymore. I'd rather them be in ./bellhop-auth-dummy/templates/login
.
Is that the correct lay of the land?
Other than bellhop
and bellhop-auth-dummy
being separate Rocket applications, I think so.
@tecywiz121 I think everything I suggested afterwards still applies. Can you take a look?
I did read your suggestions, but I don't think they'll work for my use case. I believe you presented three options:
Rocket.toml
.Here are my follow-up questions/comments.
No templates shared, create a second
Rocket.toml
This would be perfect! Since the plugin (bellhop-auth-dummy
) and the core crate (bellhop
) get compiled together into a single binary, how do I specify a second Rocket.toml
? I might have missed this in the docs, and if so, I'm sorry!
No templates shared, override with environment variable
This definitely won't work, since as far as I know, a running executable can't have multiple values for the same environment variable.
Templates are shared, use the same path
Like you mentioned, this is what I'm doing now. The problem with this approach is that it requires all plugin's templates to be added to the bellhop
crate.
This poses a significant problem if the plugins can't be released open source, which is going to be true of some of the plugins I'll be writing.
Like you mentioned, this is what I'm doing now. The problem with this approach is that it requires all plugin's templates to be added to the
bellhop
crate.
This actually touches on a bigger, more complex issue: in what way will plugins normally be "plugged in" to the overall app? And what aspects of this happen at compile time and at runtime?
Here are a few points that might help with your design:
rocket::custom
. I have several vague ideas for dealing with this:
&mut Handlebars
or &mut Tera
(with some kind of namespacing!)templates/
directories from multiple sources into one dist/
directoryThis also all depends on who--you, developers, packagers, end users, etc.--will be "choosing" plugins and what resources they will have access to at the time.
This actually touches on a bigger, more complex issue: in what way will plugins normally be "plugged in" to the overall app? And what aspects of this happen at compile time and at runtime?
I'll leave the general case up to greater minds than mine, but in Bellhop's case, the plugins are all compiled together in bellhop-bin
's main.rs
Use a compile-time template library instead
This is actually a surprisingly simple workaround. I'll go looking around, but do you have any recommendations?
Expose a method in plugin crates that would register plugin templates into an
&mut Handlebars
or&mut Tera
(with some kind of namespacing!)
I don't think it's possible to access this from the interface rocket_contrib
provides as of right now, but I think this could work too. Plus I wouldn't have to re-write all my templates!
Have some build system merge
templates/
directories from multiple sources into onedist/
directory
To do this with Cargo, I think I'd have to write a build.rs
helper library that knows where to find the source directory for dependency crates. With the hashes cargo appends, I'm not sure this would be an easy approach.
Modify Rocket's template support to look in multiple directories
This is what I had suggested in the original post: switching template_dir
to template_dirs
.
This poses a significant problem if the plugins can't be released open source, which is going to be true of some of the plugins I'll be writing.
I'll leave the general case up to greater minds than mine, but in Bellhop's case, the plugins are all compiled together in bellhop-bin's main.rs
This sounds like you need to provide plugins as .rlib
files or another non-source form. You will probably need to either use compile-time templates, embed the template files in the crate and provide them with some known global function, or distribute the template sources alongside the plugin (if that source is okay to release).
Use a compile-time template library instead
This is actually a surprisingly simple workaround. I'll go looking around, but do you have any recommendations?
askama
, horrorshow
, maud
, and ructe
are a few examples. I won't make a specific recommendation because they are very subjective and dependent on the needs of an individual project and syntax preferences.
Expose a method in plugin crates that would register plugin templates into an &mut Handlebars or &mut Tera (with some kind of namespacing!)
I don't think it's possible to access this from the interface rocket_contrib provides as of right now, but I think this could work too. Plus I wouldn't have to re-write all my templates!
Template::custom would help with this. To be clear, this approach would still require the plugin's templates to be either hardcoded into the binary (e.g. with include_str!()
), or be in something like a "bellhop_plugin_xxxxx_templates" directory at runtime.
Since this is all getting a bit off-topic from Rocket itself, I'll focus from now onward on the only thing I think Rocket is in a position to improve:
A possible solution would be to have a
template_dirs
variable that accepts an array of directories to search instead.
I think this wouldn't actually help much in your case, so I'm not (yet) convinced it should be added. A person or build process would still have to specify the multiple template_dirs
manually, and a person or build process would still have to figure out which directories have to be copied to the deployment target.
Thanks for the pointer to Template::custom
! I'm going to explore using that to set up a different template directory for each plugin, and I'll also try taking a look at askama
, which seems to have good support for Rocket.
A person or build process would still have to specify the multiple template_dirs manually, and a person or build process would still have to figure out which directories have to be copied to the deployment target.
I don't see how having multiple directories is different in that regard compared to having a single directory. Someone still has to set template_dir
in Rocket.toml
, and copy it to the deployed machine.
In my documentation for each plugin, I'd add a section like:
Installation
Attaching the Plugin
Modify your
main.rs
to look something like this:fn main() { Bellhop::default() .auth(bellhop_auth_dummy::Dummy) // Insert this line .start() }
Template Directory
Modify
Rocket.toml
:[global] template_dirs = [ "/opt/bellhop/templates", "/opt/bellhop_auth_dummy/templates", # Insert this line ]
I don't see how having multiple directories is different in that regard compared to having a single directory. Someone still has to set
template_dir
inRocket.toml
, and copy it to the deployed machine.In my documentation for each plugin, I'd add a section like:
...
For comparison I was thinking of this, which doesn't involve modifying rocket_contrib
and I think wouldn't be any more complicated to deploy than what you posted.
Installation
Attaching the Plugin
Modify your
main.rs
to look something like this:fn main() { Bellhop::default() .auth(bellhop_auth_dummy::Dummy) // Insert this line .start() }
Template Directory
Modify
Rocket.toml
:[global] template_dir ="/opt/bellhop/templates"
Where "/opt/bellhop/templates/bellhop_auth_dummy" contains the plugin templates.
The bottom line: I'm not opposed to supporting multiple template_dirs
in the future, but it's not a current priority of mine. If you or someone else is committed to or needs a design that would benefit from template_dirs
that might make it more important, but it sounds like you're still open to exploring other (possibly better) options.
I'm trying out registering a second template directory with Template::custom
over here, but I'm getting the following:
GET /extended text/html:
=> Matched: GET /extended (extended_template)
=> Error: Template 'bar' does not exist.
=> Known templates: foo
=> Searched in '"/home/sc/Personal/rocket_template_bug/templates"'.
=> Outcome: Failure
=> Warning: Responding with 500 Internal Server Error catcher.
=> Response succeeded.
The odd part is that this line prints true
.
The bottom line: I'm not opposed to supporting multiple template_dirs in the future, but it's not a current priority of mine.
That's good to hear. I'll keep investigating for now. Thanks for the help!
Aha, that's an unfortunate (and somewhat confusing) consequence of the current design. Template::render
only knows about templates discovered via the template_dir
mechanism. The inner Handlebars engine, however, does know about bar
since it was added directly -- this means that the (main crate) foo
template could reference the (plugin crate) bar
template, but Template::render
can't.
I'll have to think about this a bit more. It would be nice if templates added manually (e.g. small helpers or include_str
templates) were available to Template::render
, but I'm afraid it might be a breaking change and have other unintended consequences.
Is it possible to directly add templates to the context used by Template::render
? Looking at the code, I see that if there was a way to add templates to the context, that might address the issue.
Is it possible to directly add templates to the context used by
Template::render
? Looking at the code, I see that if there was a way to add templates to the context, that might address the issue.
As of yesterday on master
, yes.
Hey! I'm using rocket 0.4 to build a pretty simple web application, but I have some plugable modules that have their own views/templates.
I'd like to keep each module's templates with that module, but I can't figure out how to specify different
template_dir
values.This seems like it's related to #394, but is a much simpler problem to solve (if it isn't already!) A possible solution would be to have a
template_dirs
variable that accepts an array of directories to search instead.