# Cache everything but

**URL:** <https://www.ruby-forum.com/t/cache-everything-but/105381>\
**Category:** Rails\
**Created:** [May 29, 2007, 2:11pm UTC](https://www.ruby-forum.com/t/cache-everything-but/105381 "2007-05-29T14:11:47Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [May 29, 2007, 2:11pm UTC](https://www.ruby-forum.com/t/cache-everything-but/105381/1 "2007-05-29T14:11:47Z")

</div>

I saw this older post when searching for information:

On Feb 16, 5:10 pm, Ingo W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
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/](http://www.dedasys.com/davidw/)

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [May 29, 2007, 3:29pm UTC](https://www.ruby-forum.com/t/cache-everything-but/105381/2 "2007-05-29T15:29:34Z")

</div>

removed\_email\_address@domain.invalid 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](http://www.dedasys.com/davidw/)

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](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](http://rails.co.za/articles/2007/02/07/cachefilter-rails-1-2-and-edge-compatible)

HTH

Gustav P.

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [May 29, 2007, 4:04pm UTC](https://www.ruby-forum.com/t/cache-everything-but/105381/3 "2007-05-29T16:04:14Z")

</div>

> > 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](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](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/](http://www.dedasys.com/davidw/)

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [May 29, 2007, 7:14pm UTC](https://www.ruby-forum.com/t/cache-everything-but/105381/4 "2007-05-29T19:14:07Z")

</div>

> 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.

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [May 29, 2007, 8:05pm UTC](https://www.ruby-forum.com/t/cache-everything-but/105381/5 "2007-05-29T20:05:16Z")

</div>

> def after(controller)  
> return if !removed\_email\_address@domain.invalid?(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!
