So maybe this has been done before, but this is something I wrote that I
found useful.
Many of the ''fragments'' I wanted to cache differed only by
some small
value like the :id of the :url, but because this changed every request,
the options were to either store a fragment for every :id, or to not
cache.
So I wrote a helper I call ''dynamic_cache''.  It works by using
escaped
Erb INSIDE of an ERb fragment, and calling render :inline on the cached
fragment before returning.
So for instance:
<% cache do %>
 <%= link_to_remote ''My Link'', :url => { :id =>
@my_id } %>
<% end %>
This doesn''t cache, since the :id is variable.
So with dynamic_cache it would look like the following:
<% dynamic_cache do %>
 <%= link_to_remote ''My Link'', :url => { :id =>
''\<\%= @my_id \%\>'' } %>
<% end %>
@my_id doesn''t get evaluated and the escaped ERb delimiters get cleaned
up  to just ''<%= @my_id %>''. The cache then calls render
:inline on the
cached fragment which evaluates any of the newly un-escaped ERb with the
current values at the time of the render.
Add the following to your application.rb for this to work....
  module ActionController #:nodoc:
    module Caching
      module Fragments
        def dynamic_cache_erb_fragment(block, name = {}, options = nil)
          # this grabs the _erbout variable from the blocks scope
          buffer = eval(''_erbout'', block.binding)
          if ! cache = read_fragment(name, options)
            # by default the block.call will write everything to the
_erbout
            # this is an ugly way to get around that, and is the same
method used in capture_erb_with_buffer
            # but it is only called the first time, so not a big deal
            pos = buffer.length
            block.call
            cache = buffer[pos..-1]
            buffer[pos..-1] = ''''
            # save it to the cache if we are caching
            write_fragment(name, cache, options) if perform_caching
          end
          buffer.concat(render :inline => cache)
        end
      end
    end
  end
  module ActionView
    module Helpers
      module CacheHelper
        def dynamic_cache(name = {}, &block)
          @controller.dynamic_cache_erb_fragment(block, name)
        end
      end
    end
  end
-- 
Posted via http://www.ruby-forum.com/.
--~--~---------~--~----~------------~-------~--~----~
 You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Talk" group.
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en
-~----------~----~----~----~------~----~------~--~---
You can also do some more complicated caching than would otherwise be 
allowed (ie, caching larger blocks of code...it gets a little ugly, but 
may be useful.
In the following example, condtional is executed at the time of 
rendering, while the links are cached.
<% dynamic_cache do %>
  <%= ''\<\% if @my_test_value == "HURRAY"
\%\>'' %>
    <%= link_to "My Test2", "HURRAY" %>
  <%= ''\<\% else \%\>'' %>
    <%= link_to "My Test3", "HIDEYHO" %>
  <%= ''\<\% end \%\>'' %>
<% end %>
PLEASE NOTE: THERE IS A BUG HERE CURRENTLY I NEED TO FIX.  If you use 
more than one dynamic_cache request you get the a double render error. 
I need to figure out how to get the effect of render :inline with 
actually using render.
-- 
Posted via http://www.ruby-forum.com/.
--~--~---------~--~----~------------~-------~--~----~
 You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Talk" group.
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en
-~----------~----~----~----~------~----~------~--~---
OK, here is a fixed version  (just added ''@template.'' to the
render :
  module ActionController #:nodoc:
    module Caching
      module Fragments
        def dynamic_cache_erb_fragment(block, name = {}, options = nil)
          # this grabs the _erbout variable from the blocks scope
          buffer = eval(''_erbout'', block.binding)
          if ! cache = read_fragment(name, options)
            # by default the block.call will write everything to the 
_erbout
            # this is an ugly way to get around that, and is the same 
method used in capture_erb_with_buffer
            # but it is only called the first time, so not a big deal
            pos = buffer.length
            block.call
            cache = buffer[pos..-1]
            buffer[pos..-1] = ''''
            # save it to the cache if we are caching
            write_fragment(name, cache, options) if perform_caching
          end
          logger.error cache
          buffer.concat(@template.render(:inline => cache))
        end
      end
    end
  end
  module ActionView
    module Helpers
      module CacheHelper
        def dynamic_cache(name = {}, &block)
          @controller.dynamic_cache_erb_fragment(block, name)
        end
      end
    end
  end
Here is a fixed example of conditionals.  Notice the use of double 
quotes to wrap the escaped ERb.
<% dynamic_cache do %>
  <%= "\<\% if @my_test_value == \''BOOOO\''
\%\>"  %>
    <%= link_to "My Test", "/\<\%= @my_test_value
\%\>" %>
  <%= "\<\%  else \%\>" %>
    <%= link_to "My Test", "/\<\%= @my_test_value
\%\>2" %>
  <%= "\<\%  end \%\>" %>
<% end %>
Obviously, another option would be to use a separate delimiter and 
replace it with ''<%'' and ''%>'' in the
dynamic_cache method when it
initially creates the cache record.
Like,
<% dynamic_cache do %>
  <%= "#% if @my_test_value == \''BOOOO\'' %#" 
%>
    <%= link_to "My Test", "/#%= @my_test_value %#" %>
  <%= "#%  else \%\>" %#>
    <%= link_to "My Test", "/#%= @my_test_value %#>2"
%>
  <%= "#%  end %#>" %>
<% end %>
You would just need to cache.gsub for ''%#'' and
''#%'' before
write_fragment.
-- 
Posted via http://www.ruby-forum.com/.
--~--~---------~--~----~------------~-------~--~----~
 You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Talk" group.
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en
-~----------~----~----~----~------~----~------~--~---
Sorry, left a logging statement in there, which shouldnt be:
  module ActionController #:nodoc:
    module Caching
      module Fragments
        def dynamic_cache_erb_fragment(block, name = {}, options = nil)
          # this grabs the _erbout variable from the blocks scope
          buffer = eval(''_erbout'', block.binding)
          if ! cache = read_fragment(name, options)
            # by default the block.call will write everything to the 
_erbout
            # this is an ugly way to get around that, and is the same 
method used in capture_erb_with_buffer
            # but it is only called the first time, so not a big deal
            pos = buffer.length
            block.call
            cache = buffer[pos..-1]
            buffer[pos..-1] = ''''
            # save it to the cache if we are caching
            write_fragment(name, cache, options) if perform_caching
          end
          buffer.concat(@template.render(:inline => cache))
        end
      end
    end
  end
  module ActionView
    module Helpers
      module CacheHelper
        def dynamic_cache(name = {}, &block)
          @controller.dynamic_cache_erb_fragment(block, name)
        end
      end
    end
  end
-- 
Posted via http://www.ruby-forum.com/.
--~--~---------~--~----~------------~-------~--~----~
 You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Talk" group.
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en
-~----------~----~----~----~------~----~------~--~---