Cache everything but

I saw this older post when searching for information:

On Feb 16, 5:10 pm, Ingo W. [email protected]
wrote:

possible?
I have exactly the same need - a front page that has a bit of text
that changes depending on whether the user is logged in or not.
Everything else could be cached using page cacheing.

Hrm… I’ll take a look at the code… maybe something like
‘cache_except’ is possible?

Thanks,
Dave

http://www.dedasys.com/davidw/

[email protected] wrote:

content instead. A good example would be a page whereallcontent would
Everything else could be cached using page cacheing.

Hrm… I’ll take a look at the code… maybe something like
‘cache_except’ is possible?

Thanks,
Dave

David N. Welton

Hey

I had the same issue and settled for two cashed versions of my page, one
for logged in users and one for visitors.
I put the code changes into a plugin you might want to have a look at.

http://rails.co.za/articles/2007/01/10/cachefilter-update
and then some bug fixes later…
http://rails.co.za/articles/2007/02/07/cachefilter-rails-1-2-and-edge-compatible

HTH

Gustav P.

I have exactly the same need - a front page that has a bit of text
that changes depending on whether the user is logged in or not.
Everything else could be cached using page cacheing.

I had the same issue and settled for two cashed versions of my page, one
for logged in users and one for visitors.
I put the code changes into a plugin you might want to have a look at.

http://rails.co.za/articles/2007/01/10/cachefilter-update
and then some bug fixes later…http://rails.co.za/articles/2007/02/07/cachefilter-rails-1-2-and-edge

Looks like a good way of doing it.

I was thinking about something like this:

  1. Create a no_cache method as a helper. The trick is that it outputs
    something like <%= blah blah %>
  2. Cache the page.
  3. Render the cached version, which does the substitution on what
    no_cache slipped into the cache.

I don’t know whether how efficient that is, since the whole page still
has to be parsed up for erb, when there is only one little chunk of
it. I also don’t know if there are any lurking problems…

Thanks,
Dave

http://www.dedasys.com/davidw/

I was thinking about something like this:

  1. Create a no_cache method as a helper. The trick is that it outputs
    something like <%= blah blah %>
  2. Cache the page.
  3. Render the cached version, which does the substitution on what
    no_cache slipped into the cache.

Ok, some code that seems to work:

class NoCacheFilter

include ActionController::Caching::Actions

def initialize(*actions, &block)
@actions = actions
end

def before(controller)
return unless @actions.include?(controller.action_name.intern)
controller.instance_variable_set ‘@dont_interpolate_this’, true
action_cache_path = ActionCachePath.new(controller)
if cache = controller.read_fragment(action_cache_path.path)
controller.rendered_action_cache = true
set_content_type!(action_cache_path)
controller.send(:render, :inline => cache)
false
end

end

def after(controller)
return if !@actions.include?(controller.action_name.intern) ||
controller.rendered_action_cache
controller.write_fragment(ActionCachePath.path_for(controller),
controller.response.body)
controller.send(:render, :inline => controller.response.body)
end

private
def set_content_type!(action_cache_path)
if extention = action_cache_path.extension
content_type = Mime::EXTENSION_LOOKUP[extention]
action_cache_path.controller.response.content_type =
content_type.to_s
end
end

end

Combined with this helper:

def no_cache(text)
return eval(text) unless @dont_interpolate_this
return “<%= #{text} %>”
end

Things that could perhaps be improved:

  1. I don’t like setting the variable in the controller.
  2. I don’t really like the fact that no_cache takes text as an
    argument rather than somehow accomplishing the same thing with a
    block, but there’s no way to get a block’s text out, so a string it
    is, as far as I can tell.

def after(controller)
return if [email protected]?(controller.action_name.intern) ||
controller.rendered_action_cache
controller.write_fragment(ActionCachePath.path_for(controller),
controller.response.body)
controller.send(:render, :inline => controller.response.body)
end

Ugh, that isn’t quite right, either, because apparently you can’t do
any sort of render operation in the after filter, not even
render_to_string. This is pretty hacky feeling, but if that’s what it
takes…

def after(controller)
return if !@actions.include?(controller.action_name.intern) ||
controller.rendered_action_cache
controller.write_fragment(ActionCachePath.path_for(controller),
controller.response.body)
controller.instance_variable_set ‘@performed_render’, false
controller.response.body =
controller.send(:render_to_string, :inline =>
controller.response.body)
end

Cleaner ideas welcome!