config.cache_classes

Hi all,

a while ago I developed a CMS that allows user with the "designer" role to create templates. These templates are written to disk and are regular erb files. They are stored inside the app/views folder.

Back then I developed on rails 2.1 which had the config.action_view.cache_template_loading settings. That allowed me to cache the whole application, except the views (since the designer could edit them, bringing the application down-and-up wouldn't be a good idea).

After a migration to rails 2.3 I noticed this settings was gone and replaced by "config.cache_classes", which caches the application as a whole, including the views. I was forced to set the production setting to "false" in order to make it work.

The current request-response time is only 25% of the request-response time in rails 2.1 (it dropped from 20 to 6).

Is there anyone with an idea to enable the config.cache_classes, but still reload the views as necessary (faking out the old config.action_view.cache_template_loading setting)?

Cheers,

Stijn

We've had the same problem and hope it's now working like this:

http://github.com/svenfuchs/adva_cms/blob/fd7f9348b9e9cccd3ab5af2da5437e6ca6ac9e56/engines/adva_themes/lib/theme_support/compiled_template_expiration.rb

Basically, when the user saves a template we touch the theme
directory. When the template is rendered we check the directory mtime
against the compile time for that template and recompile if necessary.

It's necessary to do it this way around (instead of just expiring the
compiled/cached template in the same request when the template was
saved) because compiled templates of course are cached per process
(e.g. mongrel) and you could not expire them for all other running
processes.

Of course that code is likely to break as soon as ActionView moves by
a millimeter :wink:

Hi Sven,

thanks for pointing me in the right direction. I use a slightly different caching method, once the user logs out of the backend, 30 minutes later the cache (page caching) starts kicking in. So I added a method to my site_controller which looks like this;

  def clear_templates     ActionView::Base::CompiledTemplates.instance_methods(false).each do |method|       if method =~ /47#{@project.code}47/ # 47 is the ord of /, rails encodes methods that way         ActionView::Base::CompiledTemplates.send(:remove_method, method)       end     end     RAILS_DEFAULT_LOGGER.info("Cleared all compiled views from cache for project '#{@project.name}'")   end

After some debugging I found out that 2 methods are being "memoized" ActionView::Renderable.compiled_source and ActionView::Template.source. I think the best way to disable that behaviour would be extending the Memoizable class with a "dememoize" method (currently it only has a dememoize_all), and next dememoize those methods.

I should also mention that I'm on rails 2.2.2, I guess I was a bit confused because I just read the announcement of 2.3 RC1.

Didn't you have problems with the memoized methods when you wrote your patch?

Ah, sorry!

I should have mentioned that this worksforme on Rails 2.2 (so we've
had similar issues to yours when porting from Rails 2.1). We haven't
tried porting to Rails 2.3, yet, although we plan to do so soon.

On Rails 2.2 I haven't seen any problems with memoizing here. But
perhaps I'm still missing something.

Here is what I think that's happening;

* rails boots and start loading its template files into memory * method calls to Template.source (that loads the template from disk) and Renderable.compiled_source are memoized so it stores the result of those methods * by deleteing the necessary CompiledTempaltes, the compiled_source is being reloaded the next time the template is requested * since compiled_source is aliased by memoization, its is now replaced with a static method, thus it won't reload the Template.source * by quoting the "memoize :compile_source" line, the original method will get triggered, and now calls the source method on the template * but that's also memoized, so by unquoting that, I get the result that I need

I'm going to look further into this and hopefully let you know what solution I'll find :smiley:

Thanks for your help so far.

To conclude my journey into the rails-core, I'm posting the controller method that I've added to my application controller that forces the reload of template files, even if config.cache_classes is set to true. As said before, I trigger this function as long as the user is logged in to the backend + 30 minutes. After that template caching and page caching is kicking in.

Response times are now back as the where with rails 2.1 (maybe even a bit better, but it's hard to measure, because sites are running on the server).

On to rails 2.3, let's hope it will work there as well :slight_smile:

  def reload_templates!     # reload all templates from disk, there's no way to reload specific templates only, since the     # templates and the array that contains them, are frozen     self.response.template.view_paths.each do |view_path|       view_path.reload!     end     logger.info("Reloaded all templates from disk")

    # rails stores compiled templates as methods, so we need to remove them in order to recompile them     ActionView::Base::CompiledTemplates.instance_methods(false).each do |method|       if method =~ /47#{@project.code}47/ # 47 is the ord of /, rails encodes methods that way         ActionView::Base::CompiledTemplates.send(:remove_method, method)       end     end     logger.info("Cleared all compiled templates from cache for project '#{@project.name}'")   end

And one final itteration; I override the eager_load_templates setting, which will prevent to reload ALL templates ALL the times in non-cache mode.

module ActionView   class PathSet     class Path       # alias the eager_load_templates       class << self

alias_method :old_eager_load_templates!, :eager_load_templates!       end

      # don't eager_load_templates, even if cache_classes is turned on       def self.eager_load_templates!         @eager_load_templates = false       end     end   end end