As some of you might know, templates are not reloaded in production mode. This means that the first time a view is used, its ERB
code will be compiled to a ruby method. Something like:
_run_rhtml_app47views47versions47edit46rhtml
Don’t ask me what the ‘47’ and ‘46’ are here for. This method is called whenever we need to render using the corresponding file. If we change the file, the method is not updated in production mode. When running in development, rails executes a file stat and recompiles if the file changed.
With zena, you start the server and only then do you begin working on your templates. You write zafu code and on the first request, we build an ERB
file that sits somewhere in the site’s zafu folder.
Example of compiled template path:
sites/example.com/zafu/skin_name/Node/en/_main.erb
The first time you need to render a page with this template, rails compiles the method from erb and uses it to display the page’s content.
A little later, you change the zafu code to add a list of random images from the site. When you save, zena removes the ERB
file that was originally built.
Zena knows which files to remove by using information stored during zafu page caching with CachedPage
. Since zafu templates can be included in other templates, we might need to remove more then one file.
On the next request that needs the file for rendering, it will be rebuilt by the zafu compiler and…
... you used to see the old content.
There is a new setting in rails 2 that we need to set to false
in zena:
config.action_view.cache_template_loading = false
But this is not enough because of the way rails handles absolute paths: when you ask to render a file, rails has a complex set of rules to find a file given it’s relative path. These rules involve going through each of the paths in the PathSet
. One of these is usually “app/views”. These paths can be either instances of:
Template::EagerPath
(template not reloaded)ReloadableTemplate::ReloadablePath
(clever template reloader)That’s fine except absolute paths are not resolved with the path set and end up as simple Template
without any super powers from the reloadable team.
We could replace the simple Template
by something like the ReloadableTemplate
but then it would be reloaded on every request since we create a new object with a blank modification time (templates are used as references to files).
A ReloadableTemplate
undefines its method when it sees itself as stale? (file changed since last compilation). Since the method no longer exists, this will trigger a recompilation.
The first solution we implemented for zena quite some time ago was to put a symlink in ‘app/views’ to ‘sites’ and then render with relative urls from that point. It worked for a while and then we found weird issues with layouts. The current solution which seems clean is to add the “sites” directory to the view paths and render relatively to this folder:
# inform rails about our views ApplicationController.prepend_view_path SITES_ROOT # in the template_url resolution code: rel_path = current_site.zafu_path + fullpath path = SITES_ROOT + rel_path
Make sure you have config.action_view.cache_template_loading = false
in all environments or bad things might happen (read note).
Since we declare the SITES_ROOT
as being a place to look for templates, we should never user EagerPath
(cached templates) or rails will try to preload all content in the SITES_ROOT
directory (included images, data, etc) as templates and after eating tons of memory, this will eventually crash your computer.
Gaspard Bucher
comments
Just FYI, I’d guess the 47 and 46 are something to do with those being the ascii character codes for ’/’ and ’.’ :)
The rails internal method probably casts the path to ascii to remove any special characters in it or something.
Thanks, very useful post!
I did not think of that ! Somehow, 47 was too close to 37 to not look suspicious…