Skip to content
This repository
Browse code

extract AP Page and Action caching to actionpack-deprecated_caching gem

  • Loading branch information...
commit 2f81be178fd000956974d53ad265fffa58b50090 1 parent e4e84fe
Francesco Rodríguez authored October 03, 2012
22  actionpack/lib/action_controller/caching.rb
@@ -2,11 +2,9 @@
2 2
 require 'uri'
3 3
 require 'set'
4 4
 
5  
-module ActionController #:nodoc:
  5
+module ActionController
6 6
   # \Caching is a cheap way of speeding up slow applications by keeping the result of
7 7
   # calculations, renderings, and database calls around for subsequent requests.
8  
-  # Action Controller affords you three approaches in varying levels of granularity:
9  
-  # Page, Action, Fragment.
10 8
   #
11 9
   # You can read more about each approach and the sweeping assistance by clicking the
12 10
   # modules below.
@@ -17,8 +15,7 @@ module ActionController #:nodoc:
17 15
   # == \Caching stores
18 16
   #
19 17
   # All the caching stores from ActiveSupport::Cache are available to be used as backends
20  
-  # for Action Controller caching. This setting only affects action and fragment caching
21  
-  # as page caching is always written to disk.
  18
+  # for Action Controller caching.
22 19
   #
23 20
   # Configuration examples (MemoryStore is the default):
24 21
   #
@@ -32,9 +29,7 @@ module Caching
32 29
     extend ActiveSupport::Autoload
33 30
 
34 31
     eager_autoload do
35  
-      autoload :Actions
36 32
       autoload :Fragments
37  
-      autoload :Pages
38 33
       autoload :Sweeper, 'action_controller/caching/sweeping'
39 34
       autoload :Sweeping, 'action_controller/caching/sweeping'
40 35
     end
@@ -58,12 +53,23 @@ def cache_configured?
58 53
     include AbstractController::Callbacks
59 54
 
60 55
     include ConfigMethods
61  
-    include Pages, Actions, Fragments
  56
+    include Fragments
62 57
     include Sweeping if defined?(ActiveRecord)
63 58
 
64 59
     included do
65 60
       extend ConfigMethods
66 61
 
  62
+      # Most Rails requests do not have an extension, such as <tt>/weblog/new</tt>.
  63
+      # In these cases, the page caching mechanism will add one in order to make it
  64
+      # easy for the cached files to be picked up properly by the web server. By
  65
+      # default, this cache extension is <tt>.html</tt>. If you want something else,
  66
+      # like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension.
  67
+      # In cases where a request already has an extension, such as <tt>.xml</tt>
  68
+      # or <tt>.rss</tt>, page caching will not add an extension. This allows it
  69
+      # to work well with RESTful apps.
  70
+      config_accessor :page_cache_extension
  71
+      self.page_cache_extension ||= '.html'
  72
+
67 73
       config_accessor :perform_caching
68 74
       self.perform_caching = true if perform_caching.nil?
69 75
     end
189  actionpack/lib/action_controller/caching/actions.rb
... ...
@@ -1,189 +0,0 @@
1  
-require 'set'
2  
-
3  
-module ActionController
4  
-  module Caching
5  
-    # Action caching is similar to page caching by the fact that the entire
6  
-    # output of the response is cached, but unlike page caching, every
7  
-    # request still goes through Action Pack. The key benefit of this is
8  
-    # that filters run before the cache is served, which allows for
9  
-    # authentication and other restrictions on whether someone is allowed
10  
-    # to execute such action.
11  
-    #
12  
-    #   class ListsController < ApplicationController
13  
-    #     before_filter :authenticate, except: :public
14  
-    #
15  
-    #     caches_page   :public
16  
-    #     caches_action :index, :show
17  
-    #   end
18  
-    #
19  
-    # In this example, the +public+ action doesn't require authentication
20  
-    # so it's possible to use the faster page caching. On the other hand
21  
-    # +index+ and +show+ require authentication. They can still be cached,
22  
-    # but we need action caching for them.
23  
-    #
24  
-    # Action caching uses fragment caching internally and an around
25  
-    # filter to do the job. The fragment cache is named according to
26  
-    # the host and path of the request. A page that is accessed at
27  
-    # <tt>http://david.example.com/lists/show/1</tt> will result in a fragment named
28  
-    # <tt>david.example.com/lists/show/1</tt>. This allows the cacher to
29  
-    # differentiate between <tt>david.example.com/lists/</tt> and
30  
-    # <tt>jamis.example.com/lists/</tt> -- which is a helpful way of assisting
31  
-    # the subdomain-as-account-key pattern.
32  
-    #
33  
-    # Different representations of the same resource, e.g.
34  
-    # <tt>http://david.example.com/lists</tt> and
35  
-    # <tt>http://david.example.com/lists.xml</tt>
36  
-    # are treated like separate requests and so are cached separately.
37  
-    # Keep in mind when expiring an action cache that
38  
-    # <tt>action: 'lists'</tt> is not the same as
39  
-    # <tt>action: 'list', format: :xml</tt>.
40  
-    #
41  
-    # You can modify the default action cache path by passing a
42  
-    # <tt>:cache_path</tt> option. This will be passed directly to
43  
-    # <tt>ActionCachePath.new</tt>. This is handy for actions with
44  
-    # multiple possible routes that should be cached differently. If a
45  
-    # block is given, it is called with the current controller instance.
46  
-    #
47  
-    # And you can also use <tt>:if</tt> (or <tt>:unless</tt>) to pass a
48  
-    # proc that specifies when the action should be cached.
49  
-    #
50  
-    # As of Rails 3.0, you can also pass <tt>:expires_in</tt> with a time
51  
-    # interval (in seconds) to schedule expiration of the cached item.
52  
-    #
53  
-    # The following example depicts some of the points made above:
54  
-    #
55  
-    #   class ListsController < ApplicationController
56  
-    #     before_filter :authenticate, except: :public
57  
-    #
58  
-    #     caches_page :public
59  
-    #
60  
-    #     caches_action :index, if: Proc.new do
61  
-    #       !request.format.json?  # cache if is not a JSON request
62  
-    #     end
63  
-    #
64  
-    #     caches_action :show, cache_path: { project: 1 },
65  
-    #       expires_in: 1.hour
66  
-    #
67  
-    #     caches_action :feed, cache_path: Proc.new do
68  
-    #       if params[:user_id]
69  
-    #         user_list_url(params[:user_id, params[:id])
70  
-    #       else
71  
-    #         list_url(params[:id])
72  
-    #       end
73  
-    #     end
74  
-    #   end
75  
-    #
76  
-    # If you pass <tt>layout: false</tt>, it will only cache your action
77  
-    # content. That's useful when your layout has dynamic information.
78  
-    #
79  
-    # Warning: If the format of the request is determined by the Accept HTTP
80  
-    # header the Content-Type of the cached response could be wrong because
81  
-    # no information about the MIME type is stored in the cache key. So, if
82  
-    # you first ask for MIME type M in the Accept header, a cache entry is
83  
-    # created, and then perform a second request to the same resource asking
84  
-    # for a different MIME type, you'd get the content cached for M.
85  
-    #
86  
-    # The <tt>:format</tt> parameter is taken into account though. The safest
87  
-    # way to cache by MIME type is to pass the format in the route.
88  
-    module Actions
89  
-      extend ActiveSupport::Concern
90  
-
91  
-      module ClassMethods
92  
-        # Declares that +actions+ should be cached.
93  
-        # See ActionController::Caching::Actions for details.
94  
-        def caches_action(*actions)
95  
-          return unless cache_configured?
96  
-          options = actions.extract_options!
97  
-          options[:layout] = true unless options.key?(:layout)
98  
-          filter_options = options.extract!(:if, :unless).merge(:only => actions)
99  
-          cache_options  = options.extract!(:layout, :cache_path).merge(:store_options => options)
100  
-
101  
-          around_filter ActionCacheFilter.new(cache_options), filter_options
102  
-        end
103  
-      end
104  
-
105  
-      def _save_fragment(name, options)
106  
-        content = ""
107  
-        response_body.each do |parts|
108  
-          content << parts
109  
-        end
110  
-
111  
-        if caching_allowed?
112  
-          write_fragment(name, content, options)
113  
-        else
114  
-          content
115  
-        end
116  
-      end
117  
-
118  
-    protected
119  
-      def expire_action(options = {})
120  
-        return unless cache_configured?
121  
-
122  
-        if options.is_a?(Hash) && options[:action].is_a?(Array)
123  
-          options[:action].each {|action| expire_action(options.merge(:action => action)) }
124  
-        else
125  
-          expire_fragment(ActionCachePath.new(self, options, false).path)
126  
-        end
127  
-      end
128  
-
129  
-      class ActionCacheFilter #:nodoc:
130  
-        def initialize(options, &block)
131  
-          @cache_path, @store_options, @cache_layout =
132  
-            options.values_at(:cache_path, :store_options, :layout)
133  
-        end
134  
-
135  
-        def around(controller)
136  
-          cache_layout = @cache_layout.respond_to?(:call) ? @cache_layout.call(controller) : @cache_layout
137  
-
138  
-          path_options = if @cache_path.respond_to?(:call)
139  
-            controller.instance_exec(controller, &@cache_path)
140  
-          else
141  
-            @cache_path
142  
-          end
143  
-
144  
-          cache_path = ActionCachePath.new(controller, path_options || {})
145  
-
146  
-          body = controller.read_fragment(cache_path.path, @store_options)
147  
-
148  
-          unless body
149  
-            controller.action_has_layout = false unless cache_layout
150  
-            yield
151  
-            controller.action_has_layout = true
152  
-            body = controller._save_fragment(cache_path.path, @store_options)
153  
-          end
154  
-
155  
-          body = controller.render_to_string(:text => body, :layout => true) unless cache_layout
156  
-
157  
-          controller.response_body = body
158  
-          controller.content_type = Mime[cache_path.extension || :html]
159  
-        end
160  
-      end
161  
-
162  
-      class ActionCachePath
163  
-        attr_reader :path, :extension
164  
-
165  
-        # If +infer_extension+ is +true+, the cache path extension is looked up from the request's
166  
-        # path and format. This is desirable when reading and writing the cache, but not when
167  
-        # expiring the cache - +expire_action+ should expire the same files regardless of the
168  
-        # request format.
169  
-        def initialize(controller, options = {}, infer_extension = true)
170  
-          if infer_extension
171  
-            @extension = controller.params[:format]
172  
-            options.reverse_merge!(:format => @extension) if options.is_a?(Hash)
173  
-          end
174  
-
175  
-          path = controller.url_for(options).split('://', 2).last
176  
-          @path = normalize!(path)
177  
-        end
178  
-
179  
-      private
180  
-        def normalize!(path)
181  
-          ext = URI.parser.escape(extension) if extension
182  
-          path << 'index' if path[-1] == ?/
183  
-          path << ".#{ext}" if extension and !path.split('?', 2).first.ends_with?(".#{ext}")
184  
-          URI.parser.unescape(path)
185  
-        end
186  
-      end
187  
-    end
188  
-  end
189  
-end
202  actionpack/lib/action_controller/caching/pages.rb
... ...
@@ -1,202 +0,0 @@
1  
-require 'fileutils'
2  
-require 'active_support/core_ext/class/attribute_accessors'
3  
-
4  
-module ActionController
5  
-  module Caching
6  
-    # Page caching is an approach to caching where the entire action output of is
7  
-    # stored as a HTML file that the web server can serve without going through
8  
-    # Action Pack. This is the fastest way to cache your content as opposed to going
9  
-    # dynamically through the process of generating the content. Unfortunately, this
10  
-    # incredible speed-up is only available to stateless pages where all visitors are
11  
-    # treated the same. Content management systems -- including weblogs and wikis --
12  
-    # have many pages that are a great fit for this approach, but account-based systems
13  
-    # where people log in and manipulate their own data are often less likely candidates.
14  
-    #
15  
-    # Specifying which actions to cache is done through the +caches_page+ class method:
16  
-    #
17  
-    #   class WeblogController < ActionController::Base
18  
-    #     caches_page :show, :new
19  
-    #   end
20  
-    #
21  
-    # This will generate cache files such as <tt>weblog/show/5.html</tt> and
22  
-    # <tt>weblog/new.html</tt>, which match the URLs used that would normally trigger
23  
-    # dynamic page generation. Page caching works by configuring a web server to first
24  
-    # check for the existence of files on disk, and to serve them directly when found,
25  
-    # without passing the request through to Action Pack. This is much faster than
26  
-    # handling the full dynamic request in the usual way.
27  
-    #
28  
-    # Expiration of the cache is handled by deleting the cached file, which results
29  
-    # in a lazy regeneration approach where the cache is not restored before another
30  
-    # hit is made against it. The API for doing so mimics the options from +url_for+ and friends:
31  
-    #
32  
-    #   class WeblogController < ActionController::Base
33  
-    #     def update
34  
-    #       List.update(params[:list][:id], params[:list])
35  
-    #       expire_page action: 'show', id: params[:list][:id]
36  
-    #       redirect_to action: 'show', id: params[:list][:id]
37  
-    #     end
38  
-    #   end
39  
-    #
40  
-    # Additionally, you can expire caches using Sweepers that act on changes in
41  
-    # the model to determine when a cache is supposed to be expired.
42  
-    module Pages
43  
-      extend ActiveSupport::Concern
44  
-
45  
-      included do
46  
-        # The cache directory should be the document root for the web server and is
47  
-        # set using <tt>Base.page_cache_directory = "/document/root"</tt>. For Rails,
48  
-        # this directory has already been set to Rails.public_path (which is usually
49  
-        # set to <tt>Rails.root + "/public"</tt>). Changing this setting can be useful
50  
-        # to avoid naming conflicts with files in <tt>public/</tt>, but doing so will
51  
-        # likely require configuring your web server to look in the new location for
52  
-        # cached files.
53  
-        class_attribute :page_cache_directory
54  
-        self.page_cache_directory ||= ''
55  
-
56  
-        # Most Rails requests do not have an extension, such as <tt>/weblog/new</tt>.
57  
-        # In these cases, the page caching mechanism will add one in order to make it
58  
-        # easy for the cached files to be picked up properly by the web server. By
59  
-        # default, this cache extension is <tt>.html</tt>. If you want something else,
60  
-        # like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension.
61  
-        # In cases where a request already has an extension, such as <tt>.xml</tt>
62  
-        # or <tt>.rss</tt>, page caching will not add an extension. This allows it
63  
-        # to work well with RESTful apps.
64  
-        class_attribute :page_cache_extension
65  
-        self.page_cache_extension ||= '.html'
66  
-
67  
-        # The compression used for gzip. If +false+ (default), the page is not compressed.
68  
-        # If can be a symbol showing the ZLib compression method, for example, <tt>:best_compression</tt>
69  
-        # or <tt>:best_speed</tt> or an integer configuring the compression level.
70  
-        class_attribute :page_cache_compression
71  
-        self.page_cache_compression ||= false
72  
-      end
73  
-
74  
-      module ClassMethods
75  
-        # Expires the page that was cached with the +path+ as a key.
76  
-        #
77  
-        #   expire_page '/lists/show'
78  
-        def expire_page(path)
79  
-          return unless perform_caching
80  
-          path = page_cache_path(path)
81  
-
82  
-          instrument_page_cache :expire_page, path do
83  
-            File.delete(path) if File.exist?(path)
84  
-            File.delete(path + '.gz') if File.exist?(path + '.gz')
85  
-          end
86  
-        end
87  
-
88  
-        # Manually cache the +content+ in the key determined by +path+.
89  
-        #
90  
-        #   cache_page "I'm the cached content", '/lists/show'
91  
-        def cache_page(content, path, extension = nil, gzip = Zlib::BEST_COMPRESSION)
92  
-          return unless perform_caching
93  
-          path = page_cache_path(path, extension)
94  
-
95  
-          instrument_page_cache :write_page, path do
96  
-            FileUtils.makedirs(File.dirname(path))
97  
-            File.open(path, "wb+") { |f| f.write(content) }
98  
-            if gzip
99  
-              Zlib::GzipWriter.open(path + '.gz', gzip) { |f| f.write(content) }
100  
-            end
101  
-          end
102  
-        end
103  
-
104  
-        # Caches the +actions+ using the page-caching approach that'll store
105  
-        # the cache in a path within the +page_cache_directory+ that
106  
-        # matches the triggering url.
107  
-        #
108  
-        # You can also pass a <tt>:gzip</tt> option to override the class configuration one.
109  
-        #
110  
-        #   # cache the index action
111  
-        #   caches_page :index
112  
-        #
113  
-        #   # cache the index action except for JSON requests
114  
-        #   caches_page :index, if: Proc.new { !request.format.json? }
115  
-        #
116  
-        #   # don't gzip images
117  
-        #   caches_page :image, gzip: false
118  
-        def caches_page(*actions)
119  
-          return unless perform_caching
120  
-          options = actions.extract_options!
121  
-
122  
-          gzip_level = options.fetch(:gzip, page_cache_compression)
123  
-          gzip_level = case gzip_level
124  
-          when Symbol
125  
-            Zlib.const_get(gzip_level.upcase)
126  
-          when Fixnum
127  
-            gzip_level
128  
-          when false
129  
-            nil
130  
-          else
131  
-            Zlib::BEST_COMPRESSION
132  
-          end
133  
-
134  
-          after_filter({:only => actions}.merge(options)) do |c|
135  
-            c.cache_page(nil, nil, gzip_level)
136  
-          end
137  
-        end
138  
-
139  
-        private
140  
-          def page_cache_file(path, extension)
141  
-            name = (path.empty? || path == "/") ? "/index" : URI.parser.unescape(path.chomp('/'))
142  
-            unless (name.split('/').last || name).include? '.'
143  
-              name << (extension || self.page_cache_extension)
144  
-            end
145  
-            return name
146  
-          end
147  
-
148  
-          def page_cache_path(path, extension = nil)
149  
-            page_cache_directory.to_s + page_cache_file(path, extension)
150  
-          end
151  
-
152  
-          def instrument_page_cache(name, path)
153  
-            ActiveSupport::Notifications.instrument("#{name}.action_controller", :path => path){ yield }
154  
-          end
155  
-      end
156  
-
157  
-      # Expires the page that was cached with the +options+ as a key.
158  
-      #
159  
-      #   expire_page controller: 'lists', action: 'show'
160  
-      def expire_page(options = {})
161  
-        return unless self.class.perform_caching
162  
-
163  
-        if options.is_a?(Hash)
164  
-          if options[:action].is_a?(Array)
165  
-            options[:action].each do |action|
166  
-              self.class.expire_page(url_for(options.merge(:only_path => true, :action => action)))
167  
-            end
168  
-          else
169  
-            self.class.expire_page(url_for(options.merge(:only_path => true)))
170  
-          end
171  
-        else
172  
-          self.class.expire_page(options)
173  
-        end
174  
-      end
175  
-
176  
-      # Manually cache the +content+ in the key determined by +options+. If no content is provided,
177  
-      # the contents of response.body is used. If no options are provided, the url of the current
178  
-      # request being handled is used.
179  
-      #
180  
-      #   cache_page "I'm the cached content", controller: 'lists', action: 'show'
181  
-      def cache_page(content = nil, options = nil, gzip = Zlib::BEST_COMPRESSION)
182  
-        return unless self.class.perform_caching && caching_allowed?
183  
-
184  
-        path = case options
185  
-          when Hash
186  
-            url_for(options.merge(:only_path => true, :format => params[:format]))
187  
-          when String
188  
-            options
189  
-          else
190  
-            request.path
191  
-        end
192  
-
193  
-        if (type = Mime::LOOKUP[self.content_type]) && (type_symbol = type.symbol).present?
194  
-          extension = ".#{type_symbol}"
195  
-        end
196  
-
197  
-        self.class.cache_page(content || response.body, path, extension, gzip)
198  
-      end
199  
-
200  
-    end
201  
-  end
202  
-end
737  actionpack/test/controller/caching_test.rb
@@ -6,744 +6,40 @@
6 6
 # Don't change '/../temp/' cavalierly or you might hose something you don't want hosed
7 7
 FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
8 8
 
9  
-class CachingMetalController < ActionController::Metal
  9
+class FragmentCachingMetalTestController < ActionController::Metal
10 10
   abstract!
11 11
 
12 12
   include ActionController::Caching
13 13
 
14  
-  self.page_cache_directory = FILE_STORE_PATH
15  
-  self.cache_store = :file_store, FILE_STORE_PATH
16  
-end
17  
-
18  
-class PageCachingMetalTestController < CachingMetalController
19  
-  caches_page :ok
20  
-
21  
-  def ok
22  
-    self.response_body = 'ok'
23  
-  end
  14
+  def some_action; end
24 15
 end
25 16
 
26  
-class PageCachingMetalTest < ActionController::TestCase
27  
-  tests PageCachingMetalTestController
28  
-
  17
+class FragmentCachingMetalTest < ActionController::TestCase
29 18
   def setup
30  
-    FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
31  
-    FileUtils.mkdir_p(FILE_STORE_PATH)
32  
-  end
33  
-
34  
-  def teardown
35  
-    FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
  19
+    super
  20
+    @store = ActiveSupport::Cache::MemoryStore.new
  21
+    @controller = FragmentCachingMetalTestController.new
  22
+    @controller.perform_caching = true
  23
+    @controller.cache_store = @store
  24
+    @params = { controller: 'posts', action: 'index'}
  25
+    @request = ActionController::TestRequest.new
  26
+    @response = ActionController::TestResponse.new
  27
+    @controller.params = @params
  28
+    @controller.request = @request
  29
+    @controller.response = @response
36 30
   end
37 31
 
38  
-  def test_should_cache_get_with_ok_status
39  
-    get :ok
40  
-    assert_response :ok
41  
-    assert File.exist?("#{FILE_STORE_PATH}/page_caching_metal_test/ok.html"), 'get with ok status should have been cached'
  32
+  def test_fragment_cache_key
  33
+    assert_equal 'views/what a key', @controller.fragment_cache_key('what a key')
42 34
   end
43 35
 end
44 36
 
45  
-ActionController::Base.page_cache_directory = FILE_STORE_PATH
46  
-
47 37
 class CachingController < ActionController::Base
48 38
   abstract!
49 39
 
50 40
   self.cache_store = :file_store, FILE_STORE_PATH
51 41
 end
52 42
 
53  
-class PageCachingTestController < CachingController
54  
-  self.page_cache_compression = :best_compression
55  
-
56  
-  caches_page :ok, :no_content, :if => Proc.new { |c| !c.request.format.json? }
57  
-  caches_page :found, :not_found
58  
-  caches_page :about_me
59  
-  caches_page :default_gzip
60  
-  caches_page :no_gzip, :gzip => false
61  
-  caches_page :gzip_level, :gzip => :best_speed
62  
-
63  
-  def ok
64  
-    head :ok
65  
-  end
66  
-
67  
-  def no_content
68  
-    head :no_content
69  
-  end
70  
-
71  
-  def found
72  
-    redirect_to :action => 'ok'
73  
-  end
74  
-
75  
-  def not_found
76  
-    head :not_found
77  
-  end
78  
-
79  
-  def custom_path
80  
-    render :text => "Super soaker"
81  
-    cache_page("Super soaker", "/index.html")
82  
-  end
83  
-
84  
-  def default_gzip
85  
-    render :text => "Text"
86  
-  end
87  
-
88  
-  def no_gzip
89  
-    render :text => "PNG"
90  
-  end
91  
-
92  
-  def gzip_level
93  
-    render :text => "Big text"
94  
-  end
95  
-
96  
-  def expire_custom_path
97  
-    expire_page("/index.html")
98  
-    head :ok
99  
-  end
100  
-
101  
-  def trailing_slash
102  
-    render :text => "Sneak attack"
103  
-  end
104  
-
105  
-  def about_me
106  
-    respond_to do |format|
107  
-      format.html {render :text => 'I am html'}
108  
-      format.xml {render :text => 'I am xml'}
109  
-    end
110  
-  end
111  
-
112  
-end
113  
-
114  
-class PageCachingTest < ActionController::TestCase
115  
-  def setup
116  
-    super
117  
-
118  
-    @request = ActionController::TestRequest.new
119  
-    @request.host = 'hostname.com'
120  
-    @request.env.delete('PATH_INFO')
121  
-
122  
-    @controller = PageCachingTestController.new
123  
-    @controller.perform_caching = true
124  
-    @controller.cache_store = :file_store, FILE_STORE_PATH
125  
-
126  
-    @response   = ActionController::TestResponse.new
127  
-
128  
-    @params = {:controller => 'posts', :action => 'index', :only_path => true}
129  
-
130  
-    FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
131  
-    FileUtils.mkdir_p(FILE_STORE_PATH)
132  
-  end
133  
-
134  
-  def teardown
135  
-    FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
136  
-    @controller.perform_caching = false
137  
-  end
138  
-
139  
-  def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
140  
-    with_routing do |set|
141  
-      set.draw do
142  
-        get 'posts.:format', :to => 'posts#index', :as => :formatted_posts
143  
-        get '/', :to => 'posts#index', :as => :main
144  
-      end
145  
-      @params[:format] = 'rss'
146  
-      assert_equal '/posts.rss', @routes.url_for(@params)
147  
-      @params[:format] = nil
148  
-      assert_equal '/', @routes.url_for(@params)
149  
-    end
150  
-  end
151  
-
152  
-  def test_should_cache_get_with_ok_status
153  
-    get :ok
154  
-    assert_response :ok
155  
-    assert_page_cached :ok, "get with ok status should have been cached"
156  
-  end
157  
-
158  
-  def test_should_cache_with_custom_path
159  
-    get :custom_path
160  
-    assert File.exist?("#{FILE_STORE_PATH}/index.html")
161  
-  end
162  
-
163  
-  def test_should_expire_cache_with_custom_path
164  
-    get :custom_path
165  
-    assert File.exist?("#{FILE_STORE_PATH}/index.html")
166  
-
167  
-    get :expire_custom_path
168  
-    assert !File.exist?("#{FILE_STORE_PATH}/index.html")
169  
-  end
170  
-
171  
-  def test_should_gzip_cache
172  
-    get :custom_path
173  
-    assert File.exist?("#{FILE_STORE_PATH}/index.html.gz")
174  
-
175  
-    get :expire_custom_path
176  
-    assert !File.exist?("#{FILE_STORE_PATH}/index.html.gz")
177  
-  end
178  
-
179  
-  def test_should_allow_to_disable_gzip
180  
-    get :no_gzip
181  
-    assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/no_gzip.html")
182  
-    assert !File.exist?("#{FILE_STORE_PATH}/page_caching_test/no_gzip.html.gz")
183  
-  end
184  
-
185  
-  def test_should_use_config_gzip_by_default
186  
-    @controller.expects(:cache_page).with(nil, nil, Zlib::BEST_COMPRESSION)
187  
-    get :default_gzip
188  
-  end
189  
-
190  
-  def test_should_set_gzip_level
191  
-    @controller.expects(:cache_page).with(nil, nil, Zlib::BEST_SPEED)
192  
-    get :gzip_level
193  
-  end
194  
-
195  
-  def test_should_cache_without_trailing_slash_on_url
196  
-    @controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash'
197  
-    assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html")
198  
-  end
199  
-
200  
-  def test_should_obey_http_accept_attribute
201  
-    @request.env['HTTP_ACCEPT'] = 'text/xml'
202  
-    get :about_me
203  
-    assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/about_me.xml")
204  
-    assert_equal 'I am xml', @response.body
205  
-  end
206  
-
207  
-  def test_cached_page_should_not_have_trailing_slash_even_if_url_has_trailing_slash
208  
-    @controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash/'
209  
-    assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html")
210  
-  end
211  
-
212  
-  def test_should_cache_ok_at_custom_path
213  
-    @request.env['PATH_INFO'] = '/index.html'
214  
-    get :ok
215  
-    assert_response :ok
216  
-    assert File.exist?("#{FILE_STORE_PATH}/index.html")
217  
-  end
218  
-
219  
-  [:ok, :no_content, :found, :not_found].each do |status|
220  
-    [:get, :post, :patch, :put, :delete].each do |method|
221  
-      unless method == :get && status == :ok
222  
-        define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
223  
-          send(method, status)
224  
-          assert_response status
225  
-          assert_page_not_cached status, "#{method} with #{status} status shouldn't have been cached"
226  
-        end
227  
-      end
228  
-    end
229  
-  end
230  
-
231  
-  def test_page_caching_conditional_options
232  
-    get :ok, :format=>'json'
233  
-    assert_page_not_cached :ok
234  
-  end
235  
-
236  
-  def test_page_caching_directory_set_as_pathname
237  
-    begin
238  
-      ActionController::Base.page_cache_directory = Pathname.new(FILE_STORE_PATH)
239  
-      get :ok
240  
-      assert_response :ok
241  
-      assert_page_cached :ok
242  
-    ensure
243  
-      ActionController::Base.page_cache_directory = FILE_STORE_PATH
244  
-    end
245  
-  end
246  
-
247  
-  private
248  
-    def assert_page_cached(action, message = "#{action} should have been cached")
249  
-      assert page_cached?(action), message
250  
-    end
251  
-
252  
-    def assert_page_not_cached(action, message = "#{action} shouldn't have been cached")
253  
-      assert !page_cached?(action), message
254  
-    end
255  
-
256  
-    def page_cached?(action)
257  
-      File.exist? "#{FILE_STORE_PATH}/page_caching_test/#{action}.html"
258  
-    end
259  
-end
260  
-
261  
-class ActionCachingTestController < CachingController
262  
-  rescue_from(Exception) { head 500 }
263  
-  rescue_from(ActionController::UnknownFormat) { head :not_acceptable }
264  
-  if defined? ActiveRecord
265  
-    rescue_from(ActiveRecord::RecordNotFound) { head :not_found }
266  
-  end
267  
-
268  
-  # Eliminate uninitialized ivar warning
269  
-  before_filter { @title = nil }
270  
-
271  
-  caches_action :index, :redirected, :forbidden, :if => Proc.new { |c| c.request.format && !c.request.format.json? }, :expires_in => 1.hour
272  
-  caches_action :show, :cache_path => 'http://test.host/custom/show'
273  
-  caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" }
274  
-  caches_action :with_layout
275  
-  caches_action :with_format_and_http_param, :cache_path => Proc.new { |c| { :key => 'value' } }
276  
-  caches_action :layout_false, :layout => false
277  
-  caches_action :with_layout_proc_param, :layout => Proc.new { |c| c.params[:layout] }
278  
-  caches_action :record_not_found, :four_oh_four, :simple_runtime_error
279  
-  caches_action :streaming
280  
-  caches_action :invalid
281  
-
282  
-  layout 'talk_from_action'
283  
-
284  
-  def index
285  
-    @cache_this = MockTime.now.to_f.to_s
286  
-    render :text => @cache_this
287  
-  end
288  
-
289  
-  def redirected
290  
-    redirect_to :action => 'index'
291  
-  end
292  
-
293  
-  def forbidden
294  
-    render :text => "Forbidden"
295  
-    response.status = "403 Forbidden"
296  
-  end
297  
-
298  
-  def with_layout
299  
-    @cache_this = MockTime.now.to_f.to_s
300  
-    @title = nil
301  
-    render :text => @cache_this, :layout => true
302  
-  end
303  
-
304  
-  def with_format_and_http_param
305  
-    @cache_this = MockTime.now.to_f.to_s
306  
-    render :text => @cache_this
307  
-  end
308  
-
309  
-  def record_not_found
310  
-    raise ActiveRecord::RecordNotFound, "oops!"
311  
-  end
312  
-
313  
-  def four_oh_four
314  
-    render :text => "404'd!", :status => 404
315  
-  end
316  
-
317  
-  def simple_runtime_error
318  
-    raise "oops!"
319  
-  end
320  
-
321  
-  alias_method :show, :index
322  
-  alias_method :edit, :index
323  
-  alias_method :destroy, :index
324  
-  alias_method :layout_false, :with_layout
325  
-  alias_method :with_layout_proc_param, :with_layout
326  
-
327  
-  def expire
328  
-    expire_action :controller => 'action_caching_test', :action => 'index'
329  
-    render :nothing => true
330  
-  end
331  
-
332  
-  def expire_xml
333  
-    expire_action :controller => 'action_caching_test', :action => 'index', :format => 'xml'
334  
-    render :nothing => true
335  
-  end
336  
-
337  
-  def expire_with_url_string
338  
-    expire_action url_for(:controller => 'action_caching_test', :action => 'index')
339  
-    render :nothing => true
340  
-  end
341  
-
342  
-  def streaming
343  
-    render :text => "streaming", :stream => true
344  
-  end
345  
-
346  
-  def invalid
347  
-    @cache_this = MockTime.now.to_f.to_s
348  
-
349  
-    respond_to do |format|
350  
-      format.json{ render :json => @cache_this }
351  
-    end
352  
-  end
353  
-end
354  
-
355  
-class MockTime < Time
356  
-  # Let Time spicy to assure that Time.now != Time.now
357  
-  def to_f
358  
-    super+rand
359  
-  end
360  
-end
361  
-
362  
-class ActionCachingMockController
363  
-  attr_accessor :mock_url_for
364  
-  attr_accessor :mock_path
365  
-
366  
-  def initialize
367  
-    yield self if block_given?
368  
-  end
369  
-
370  
-  def url_for(*args)
371  
-    @mock_url_for
372  
-  end
373  
-
374  
-  def params
375  
-    request.parameters
376  
-  end
377  
-
378  
-  def request
379  
-    Object.new.instance_eval(<<-EVAL)
380  
-      def path; '#{@mock_path}' end
381  
-      def format; 'all' end
382  
-      def parameters; {:format => nil}; end
383  
-      self
384  
-    EVAL
385  
-  end
386  
-end
387  
-
388  
-class ActionCacheTest < ActionController::TestCase
389  
-  tests ActionCachingTestController
390  
-
391  
-  def setup
392  
-    super
393  
-    @request.host = 'hostname.com'
394  
-    FileUtils.mkdir_p(FILE_STORE_PATH)
395  
-    @path_class = ActionController::Caching::Actions::ActionCachePath
396  
-    @mock_controller = ActionCachingMockController.new
397  
-  end
398  
-
399  
-  def teardown
400  
-    super
401  
-    FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
402  
-  end
403  
-
404  
-  def test_simple_action_cache
405  
-    get :index
406  
-    assert_response :success
407  
-    cached_time = content_to_cache
408  
-    assert_equal cached_time, @response.body
409  
-    assert fragment_exist?('hostname.com/action_caching_test')
410  
-
411  
-    get :index
412  
-    assert_response :success
413  
-    assert_equal cached_time, @response.body
414  
-  end
415  
-
416  
-  def test_simple_action_not_cached
417  
-    get :destroy
418  
-    assert_response :success
419  
-    cached_time = content_to_cache
420  
-    assert_equal cached_time, @response.body
421  
-    assert !fragment_exist?('hostname.com/action_caching_test/destroy')
422  
-
423  
-    get :destroy
424  
-    assert_response :success
425  
-    assert_not_equal cached_time, @response.body
426  
-  end
427  
-
428  
-  include RackTestUtils
429  
-
430  
-  def test_action_cache_with_layout
431  
-    get :with_layout
432  
-    assert_response :success
433  
-    cached_time = content_to_cache
434  
-    assert_not_equal cached_time, @response.body
435  
-    assert fragment_exist?('hostname.com/action_caching_test/with_layout')
436  
-
437  
-    get :with_layout
438  
-    assert_response :success
439  
-    assert_not_equal cached_time, @response.body
440  
-    body = body_to_string(read_fragment('hostname.com/action_caching_test/with_layout'))
441  
-    assert_equal @response.body, body
442  
-  end
443  
-
444  
-  def test_action_cache_with_layout_and_layout_cache_false
445  
-    get :layout_false
446  
-    assert_response :success
447  
-    cached_time = content_to_cache
448  
-    assert_not_equal cached_time, @response.body
449  
-    assert fragment_exist?('hostname.com/action_caching_test/layout_false')
450  
-
451  
-    get :layout_false
452  
-    assert_response :success
453  
-    assert_not_equal cached_time, @response.body
454  
-    body = body_to_string(read_fragment('hostname.com/action_caching_test/layout_false'))
455  
-    assert_equal cached_time, body
456  
-  end
457  
-
458  
-  def test_action_cache_with_layout_and_layout_cache_false_via_proc
459  
-    get :with_layout_proc_param, :layout => false
460  
-    assert_response :success
461  
-    cached_time = content_to_cache
462  
-    assert_not_equal cached_time, @response.body
463  
-    assert fragment_exist?('hostname.com/action_caching_test/with_layout_proc_param')
464  
-
465  
-    get :with_layout_proc_param, :layout => false
466  
-    assert_response :success
467  
-    assert_not_equal cached_time, @response.body
468  
-    body = body_to_string(read_fragment('hostname.com/action_caching_test/with_layout_proc_param'))
469  
-    assert_equal cached_time, body
470  
-  end
471  
-
472  
-  def test_action_cache_with_layout_and_layout_cache_true_via_proc
473  
-    get :with_layout_proc_param, :layout => true
474  
-    assert_response :success
475  
-    cached_time = content_to_cache
476  
-    assert_not_equal cached_time, @response.body
477  
-    assert fragment_exist?('hostname.com/action_caching_test/with_layout_proc_param')
478  
-
479  
-    get :with_layout_proc_param, :layout => true
480  
-    assert_response :success
481  
-    assert_not_equal cached_time, @response.body
482  
-    body = body_to_string(read_fragment('hostname.com/action_caching_test/with_layout_proc_param'))
483  
-    assert_equal @response.body, body
484  
-  end
485  
-
486  
-  def test_action_cache_conditional_options
487  
-    @request.env['HTTP_ACCEPT'] = 'application/json'
488  
-    get :index
489  
-    assert_response :success
490  
-    assert !fragment_exist?('hostname.com/action_caching_test')
491  
-  end
492  
-
493  
-  def test_action_cache_with_format_and_http_param
494  
-    get :with_format_and_http_param, :format => 'json'
495  
-    assert_response :success
496  
-    assert !fragment_exist?('hostname.com/action_caching_test/with_format_and_http_param.json?key=value.json')
497  
-    assert fragment_exist?('hostname.com/action_caching_test/with_format_and_http_param.json?key=value')
498  
-  end
499  
-
500  
-  def test_action_cache_with_store_options
501  
-    MockTime.expects(:now).returns(12345).once
502  
-    @controller.expects(:read_fragment).with('hostname.com/action_caching_test', :expires_in => 1.hour).once
503  
-    @controller.expects(:write_fragment).with('hostname.com/action_caching_test', '12345.0', :expires_in => 1.hour).once
504  
-    get :index
505  
-    assert_response :success
506  
-  end
507  
-
508  
-  def test_action_cache_with_custom_cache_path
509  
-    get :show
510  
-    assert_response :success
511  
-    cached_time = content_to_cache
512  
-    assert_equal cached_time, @response.body
513  
-    assert fragment_exist?('test.host/custom/show')
514  
-
515  
-    get :show
516  
-    assert_response :success
517  
-    assert_equal cached_time, @response.body
518  
-  end
519  
-
520  
-  def test_action_cache_with_custom_cache_path_in_block
521  
-    get :edit
522  
-    assert_response :success
523  
-    assert fragment_exist?('test.host/edit')
524  
-
525  
-    get :edit, :id => 1
526  
-    assert_response :success
527  
-    assert fragment_exist?('test.host/1;edit')
528  
-  end
529  
-
530  
-  def test_cache_expiration
531  
-    get :index
532  
-    assert_response :success
533  
-    cached_time = content_to_cache
534  
-
535  
-    get :index
536  
-    assert_response :success
537  
-    assert_equal cached_time, @response.body
538  
-
539  
-    get :expire
540  
-    assert_response :success
541  
-
542  
-    get :index
543  
-    assert_response :success
544  
-    new_cached_time = content_to_cache
545  
-    assert_not_equal cached_time, @response.body
546  
-
547  
-    get :index
548  
-    assert_response :success
549  
-    assert_equal new_cached_time, @response.body
550  
-  end
551  
-
552  
-  def test_cache_expiration_isnt_affected_by_request_format
553  
-    get :index
554  
-    cached_time = content_to_cache
555  
-
556  
-    @request.request_uri = "/action_caching_test/expire.xml"
557  
-    get :expire, :format => :xml
558  
-    assert_response :success
559  
-
560  
-    get :index
561  
-    assert_response :success
562  
-    assert_not_equal cached_time, @response.body
563  
-  end
564  
-
565  
-  def test_cache_expiration_with_url_string
566  
-    get :index
567  
-    cached_time = content_to_cache
568  
-
569  
-    @request.request_uri = "/action_caching_test/expire_with_url_string"
570  
-    get :expire_with_url_string
571  
-    assert_response :success
572  
-
573  
-    get :index
574  
-    assert_response :success
575  
-    assert_not_equal cached_time, @response.body
576  
-  end
577  
-
578  
-  def test_cache_is_scoped_by_subdomain
579  
-    @request.host = 'jamis.hostname.com'
580  
-    get :index
581  
-    assert_response :success
582  
-    jamis_cache = content_to_cache
583  
-
584  
-    @request.host = 'david.hostname.com'
585  
-    get :index
586  
-    assert_response :success
587  
-    david_cache = content_to_cache
588  
-    assert_not_equal jamis_cache, @response.body
589  
-
590  
-    @request.host = 'jamis.hostname.com'
591  
-    get :index
592  
-    assert_response :success
593  
-    assert_equal jamis_cache, @response.body
594  
-
595  
-    @request.host = 'david.hostname.com'
596  
-    get :index
597  
-    assert_response :success
598  
-    assert_equal david_cache, @response.body
599  
-  end
600  
-
601  
-  def test_redirect_is_not_cached
602  
-    get :redirected
603  
-    assert_response :redirect
604  
-    get :redirected
605  
-    assert_response :redirect
606  
-  end
607  
-
608  
-  def test_forbidden_is_not_cached
609  
-    get :forbidden
610  
-    assert_response :forbidden
611  
-    get :forbidden
612  
-    assert_response :forbidden
613  
-  end
614  
-
615  
-  def test_xml_version_of_resource_is_treated_as_different_cache
616  
-    with_routing do |set|
617  
-      set.draw do
618  
-        get ':controller(/:action(.:format))'
619  
-      end
620  
-
621  
-      get :index, :format => 'xml'
622  
-      assert_response :success
623  
-      cached_time = content_to_cache
624  
-      assert_equal cached_time, @response.body
625  
-      assert fragment_exist?('hostname.com/action_caching_test/index.xml')
626  
-
627  
-      get :index, :format => 'xml'
628  
-      assert_response :success
629  
-      assert_equal cached_time, @response.body
630  
-      assert_equal 'application/xml', @response.content_type
631  
-
632  
-      get :expire_xml
633  
-      assert_response :success
634  
-
635  
-      get :index, :format => 'xml'
636  
-      assert_response :success
637  
-      assert_not_equal cached_time, @response.body