From c6d72608418989952dbb9a9b09d42c0eed74b9f1 Mon Sep 17 00:00:00 2001
From: Rick Olson <technoweenie@gmail.com>
Date: Thu, 22 Mar 2007 10:12:34 +0000
Subject: Allow configuration of the default action cache path for
 #caches_action calls.  [Rick Olson]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@6453 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
---
 actionpack/CHANGELOG                        |  9 +++++++++
 actionpack/lib/action_controller/caching.rb | 28 ++++++++++++++++++++++++--
 actionpack/test/controller/caching_test.rb  | 31 +++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index ecfebf7e67..d41d2dc550 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,14 @@
 *SVN*
 
+* Allow configuration of the default action cache path for #caches_action calls.  [Rick Olson]
+
+  class ListsController < ApplicationController
+    caches_action :index, :cache_path => Proc.new { |controller| 
+      controller.params[:user_id] ? 
+        controller.send(:user_lists_url, c.params[:user_id]) :
+        controller.send(:lists_url) }
+  end
+
 * Performance: patch cgi/session/pstore to require digest/md5 once rather than per #initialize.  #7583 [Stefan Kaes]
 
 * Cookie session store: ensure that new sessions doesn't reuse data from a deleted session in the same request.  [Jeremy Kemper]
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb
index d016d09baa..94d2ede685 100644
--- a/actionpack/lib/action_controller/caching.rb
+++ b/actionpack/lib/action_controller/caching.rb
@@ -161,6 +161,19 @@ module ActionController #:nodoc:
     # Different representations of the same resource, e.g. <tt>http://david.somewhere.com/lists</tt> and <tt>http://david.somewhere.com/lists.xml</tt>
     # are treated like separate requests and so are cached separately. Keep in mind when expiring an action cache that <tt>:action => 'lists'</tt> is not the same
     # as <tt>:action => 'list', :format => :xml</tt>.
+    #
+    # You can set modify the default action cache path by passing a :cache_path option.  This will be passed directly to ActionCachePath.path_for.  This is handy
+    # for actions with multiple possible routes that should be cached differently.  If a block is given, it is called with the current controller instance.
+    #
+    #   class ListsController < ApplicationController
+    #     before_filter :authenticate, :except => :public
+    #     caches_page   :public
+    #     caches_action :show, :cache_path => { :project => 1 }
+    #     caches_action :show, :cache_path => Proc.new { |controller| 
+    #       controller.params[:user_id] ? 
+    #         controller.send(:user_list_url, c.params[:user_id], c.params[:id]) :
+    #         controller.send(:list_url, c.params[:id]) }
+    #   end
     module Actions
       def self.included(base) #:nodoc:
         base.extend(ClassMethods)
@@ -188,11 +201,12 @@ module ActionController #:nodoc:
       class ActionCacheFilter #:nodoc:
         def initialize(*actions, &block)
           @actions = actions
+          @options = @actions.last.is_a?(Hash) ? @actions.pop : {}
         end
 
         def before(controller)
           return unless @actions.include?(controller.action_name.intern)
-          action_cache_path = ActionCachePath.new(controller)
+          action_cache_path = ActionCachePath.new(controller, path_options_for(controller))
           if cache = controller.read_fragment(action_cache_path.path)
             controller.rendered_action_cache = true
             set_content_type!(action_cache_path)
@@ -203,7 +217,7 @@ module ActionController #:nodoc:
 
         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.write_fragment(ActionCachePath.path_for(controller, path_options_for(controller)), controller.response.body)
         end
         
         private
@@ -215,6 +229,10 @@ module ActionController #:nodoc:
             end
           end
           
+          def path_options_for(controller)
+            (@options[:cache_path].respond_to?(:call) ? @options[:cache_path].call(controller) : @options[:cache_path]) || {}
+          end
+          
       end
       
       class ActionCachePath
@@ -598,6 +616,12 @@ module ActionController #:nodoc:
           self.controller = nil
         end
 
+        protected
+          # gets the action cache path for the given options.
+          def action_path_for(options)
+            ActionController::Caching::Actions::ActionCachePath.path_for(controller, options)
+          end
+
         private
           def callback(timing)
             controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}"
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 53db8ad843..b5846acafd 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -98,11 +98,16 @@ end
 
 class ActionCachingTestController < ActionController::Base
   caches_action :index
+  caches_action :show, :cache_path => 'http://test.host/custom/show'
+  caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" }
 
   def index
     @cache_this = Time.now.to_f.to_s
     render :text => @cache_this
   end
+  
+  alias_method :show, :index
+  alias_method :edit, :index
 
   def expire
     expire_action :controller => 'action_caching_test', :action => 'index'
@@ -148,11 +153,32 @@ class ActionCacheTest < Test::Unit::TestCase
     get :index
     cached_time = content_to_cache
     assert_equal cached_time, @response.body
+    assert_cache_exists 'hostname.com/action_caching_test'
     reset!
 
     get :index
     assert_equal cached_time, @response.body
   end
+  
+  def test_action_cache_with_custom_cache_path
+    get :show
+    cached_time = content_to_cache
+    assert_equal cached_time, @response.body
+    assert_cache_exists 'test.host/custom/show'
+    reset!
+
+    get :show
+    assert_equal cached_time, @response.body
+  end
+
+  def test_action_cache_with_custom_cache_path_in_block
+    get :edit
+    assert_cache_exists 'test.host/edit'
+    reset!
+
+    get :edit, :id => 1
+    assert_cache_exists 'test.host/1;edit'
+  end
 
   def test_cache_expiration
     get :index
@@ -228,4 +254,9 @@ class ActionCacheTest < Test::Unit::TestCase
       @controller = ActionCachingTestController.new
       @request.host = 'hostname.com'
     end
+    
+    def assert_cache_exists(path)
+      full_path = File.join(FILE_STORE_PATH, path + '.cache')
+      assert File.exist?(full_path), "#{full_path.inspect} does not exist."
+    end
 end
-- 
cgit v1.2.3