1. Template reloading in production mode

    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.

    zafu

    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.

    template caching issues

    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.

    solution

    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

    1. Thursday, November 05 2009 17:40 Joe Pym

      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!

    2. Monday, November 09 2009 21:54 Gaspard Bucher

      I did not think of that ! Somehow, 47 was too close to 37 to not look suspicious…