actionpack-page_caching 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack-page_caching might be problematic. Click here for more details.

@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+ before_install:
3
+ - gem install bundler
4
+ rvm:
5
+ - 1.9.3
6
+ notifications:
7
+ email: false
8
+ irc:
9
+ on_success: change
10
+ on_failure: always
11
+ channels:
12
+ - "irc.freenode.org#rails-contrib"
13
+ campfire:
14
+ on_success: change
15
+ on_failure: always
16
+ rooms:
17
+ - secure: "eRCx+FMvH50pmLu0GZTF7NN+2X+CesgodYUlHvCr5EXQ0ZO/YUmeW8vAh/N8\njSrLWYpk/4P/JA63JGWsvFor/zpkTnfwzX3LWgw04GV0V3T9jsn9CD2Coiu6\nFll5u4fUCUwpfbB4RlCkjvFdQmW+F9mmbRGMCDO5CmuPHOyyPH0="
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rails', '~> 4.0.0.beta1'
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 David Heinemeier Hansson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,69 @@
1
+ actionpack-page_caching
2
+ =======================
3
+
4
+ Static page caching for Action Pack (removed from core in Rails 4.0)
5
+
6
+ Installation
7
+ ------------
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'actionpack-page_caching'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install actionpack-page_caching
20
+
21
+ Usage
22
+ -----
23
+
24
+ Page caching is an approach to caching where the entire action output of is
25
+ stored as a HTML file that the web server can serve without going through
26
+ Action Pack. This is the fastest way to cache your content as opposed to going
27
+ dynamically through the process of generating the content. Unfortunately, this
28
+ incredible speed-up is only available to stateless pages where all visitors are
29
+ treated the same. Content management systems -- including weblogs and wikis --
30
+ have many pages that are a great fit for this approach, but account-based systems
31
+ where people log in and manipulate their own data are often less likely candidates.
32
+
33
+ Specifying which actions to cache is done through the `caches_page` class method:
34
+
35
+ class WeblogController < ActionController::Base
36
+ caches_page :show, :new
37
+ end
38
+
39
+ This will generate cache files such as `weblog/show/5.html` and
40
+ `weblog/new.html`, which match the URLs used that would normally trigger
41
+ dynamic page generation. Page caching works by configuring a web server to first
42
+ check for the existence of files on disk, and to serve them directly when found,
43
+ without passing the request through to Action Pack. This is much faster than
44
+ handling the full dynamic request in the usual way.
45
+
46
+ Expiration of the cache is handled by deleting the cached file, which results
47
+ in a lazy regeneration approach where the cache is not restored before another
48
+ hit is made against it. The API for doing so mimics the options from `url_for`
49
+ and friends:
50
+
51
+ class WeblogController < ActionController::Base
52
+ def update
53
+ List.update(params[:list][:id], params[:list])
54
+ expire_page action: 'show', id: params[:list][:id]
55
+ redirect_to action: 'show', id: params[:list][:id]
56
+ end
57
+ end
58
+
59
+ Additionally, you can expire caches using [Sweepers](http://edgeapi.rubyonrails.org/classes/ActionController/Caching/Sweeping.html)
60
+ that act on changes in the model to determine when a cache is supposed to be expired.
61
+
62
+ Contributing
63
+ ------------
64
+
65
+ 1. Fork it.
66
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
67
+ 3. Commit your changes (`git commit -am 'Add some feature'`).
68
+ 4. Push to the branch (`git push origin my-new-feature`).
69
+ 5. Create a new Pull Request.
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs = ['test']
7
+ t.pattern = 'test/**/*_test.rb'
8
+ t.ruby_opts = ['-w']
9
+ end
10
+
11
+ task default: :test
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'actionpack-page_caching'
5
+ gem.version = '1.0.0'
6
+ gem.author = 'David Heinemeier Hansson'
7
+ gem.email = 'david@loudthinking.com'
8
+ gem.description = 'Static page caching for Action Pack (removed from core in Rails 4.0)'
9
+ gem.summary = 'Static page caching for Action Pack (removed from core in Rails 4.0)'
10
+ gem.homepage = 'https://github.com/rails/actionpack-page_caching'
11
+
12
+ gem.files = `git ls-files`.split($/)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.require_paths = ['lib']
16
+
17
+ gem.add_dependency 'actionpack', '>= 4.0.0.beta', '< 5.0'
18
+
19
+ gem.add_development_dependency 'mocha'
20
+ end
@@ -0,0 +1,194 @@
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
+ # The compression used for gzip. If +false+ (default), the page is not compressed.
57
+ # If can be a symbol showing the ZLib compression method, for example, <tt>:best_compression</tt>
58
+ # or <tt>:best_speed</tt> or an integer configuring the compression level.
59
+ class_attribute :page_cache_compression
60
+ self.page_cache_compression ||= false
61
+ end
62
+
63
+ module ClassMethods
64
+ # Expires the page that was cached with the +path+ as a key.
65
+ #
66
+ # expire_page '/lists/show'
67
+ def expire_page(path)
68
+ return unless perform_caching
69
+ path = page_cache_path(path)
70
+
71
+ instrument_page_cache :expire_page, path do
72
+ File.delete(path) if File.exist?(path)
73
+ File.delete(path + '.gz') if File.exist?(path + '.gz')
74
+ end
75
+ end
76
+
77
+ # Manually cache the +content+ in the key determined by +path+.
78
+ #
79
+ # cache_page "I'm the cached content", '/lists/show'
80
+ def cache_page(content, path, extension = nil, gzip = Zlib::BEST_COMPRESSION)
81
+ return unless perform_caching
82
+ path = page_cache_path(path, extension)
83
+
84
+ instrument_page_cache :write_page, path do
85
+ FileUtils.makedirs(File.dirname(path))
86
+ File.open(path, 'wb+') { |f| f.write(content) }
87
+ if gzip
88
+ Zlib::GzipWriter.open(path + '.gz', gzip) { |f| f.write(content) }
89
+ end
90
+ end
91
+ end
92
+
93
+ # Caches the +actions+ using the page-caching approach that'll store
94
+ # the cache in a path within the +page_cache_directory+ that
95
+ # matches the triggering url.
96
+ #
97
+ # You can also pass a <tt>:gzip</tt> option to override the class configuration one.
98
+ #
99
+ # # cache the index action
100
+ # caches_page :index
101
+ #
102
+ # # cache the index action except for JSON requests
103
+ # caches_page :index, if: Proc.new { !request.format.json? }
104
+ #
105
+ # # don't gzip images
106
+ # caches_page :image, gzip: false
107
+ def caches_page(*actions)
108
+ return unless perform_caching
109
+ options = actions.extract_options!
110
+
111
+ gzip_level = options.fetch(:gzip, page_cache_compression)
112
+ gzip_level = case gzip_level
113
+ when Symbol
114
+ Zlib.const_get(gzip_level.upcase)
115
+ when Fixnum
116
+ gzip_level
117
+ when false
118
+ nil
119
+ else
120
+ Zlib::BEST_COMPRESSION
121
+ end
122
+
123
+ after_filter({only: actions}.merge(options)) do |c|
124
+ c.cache_page(nil, nil, gzip_level)
125
+ end
126
+ end
127
+
128
+ private
129
+ def page_cache_file(path, extension)
130
+ name = (path.empty? || path == '/') ? '/index' : URI.parser.unescape(path.chomp('/'))
131
+ unless (name.split('/').last || name).include? '.'
132
+ name << (extension || self.default_static_extension)
133
+ end
134
+ return name
135
+ end
136
+
137
+ def page_cache_path(path, extension = nil)
138
+ page_cache_directory.to_s + page_cache_file(path, extension)
139
+ end
140
+
141
+ def instrument_page_cache(name, path)
142
+ ActiveSupport::Notifications.instrument("#{name}.action_controller", path: path){ yield }
143
+ end
144
+ end
145
+
146
+ # Expires the page that was cached with the +options+ as a key.
147
+ #
148
+ # expire_page controller: 'lists', action: 'show'
149
+ def expire_page(options = {})
150
+ return unless self.class.perform_caching
151
+
152
+ if options.is_a?(Hash)
153
+ if options[:action].is_a?(Array)
154
+ options[:action].each do |action|
155
+ self.class.expire_page(url_for(options.merge(only_path: true, action: action)))
156
+ end
157
+ else
158
+ self.class.expire_page(url_for(options.merge(only_path: true)))
159
+ end
160
+ else
161
+ self.class.expire_page(options)
162
+ end
163
+ end
164
+
165
+ # Manually cache the +content+ in the key determined by +options+. If no content is provided,
166
+ # the contents of response.body is used. If no options are provided, the url of the current
167
+ # request being handled is used.
168
+ #
169
+ # cache_page "I'm the cached content", controller: 'lists', action: 'show'
170
+ def cache_page(content = nil, options = nil, gzip = Zlib::BEST_COMPRESSION)
171
+ return unless self.class.perform_caching && caching_allowed?
172
+
173
+ path = case options
174
+ when Hash
175
+ url_for(options.merge(only_path: true, format: params[:format]))
176
+ when String
177
+ options
178
+ else
179
+ request.path
180
+ end
181
+
182
+ if (type = Mime::LOOKUP[self.content_type]) && (type_symbol = type.symbol).present?
183
+ extension = ".#{type_symbol}"
184
+ end
185
+
186
+ self.class.cache_page(content || response.body, path, extension, gzip)
187
+ end
188
+
189
+ def caching_allowed?
190
+ (request.get? || request.head?) && response.status == 200
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,9 @@
1
+ module ActionController
2
+ module Caching
3
+ eager_autoload do
4
+ autoload :Pages
5
+ end
6
+
7
+ include Pages
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ require 'action_controller/page_caching'
@@ -0,0 +1,22 @@
1
+ require 'bundler/setup'
2
+ require 'minitest/autorun'
3
+ require 'action_controller'
4
+ require 'action_controller/page_caching'
5
+
6
+ SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
7
+
8
+ module ActionController
9
+ class Base
10
+ include SharedTestRoutes.url_helpers
11
+ end
12
+
13
+ class TestCase
14
+ def setup
15
+ @routes = SharedTestRoutes
16
+
17
+ @routes.draw do
18
+ get ':controller(/:action)'
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,265 @@
1
+ require 'abstract_unit'
2
+
3
+ CACHE_DIR = 'test_cache'
4
+ # Don't change '/../temp/' cavalierly or you might hose something you don't want hosed
5
+ FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
6
+
7
+ class CachingMetalController < ActionController::Metal
8
+ abstract!
9
+
10
+ include ActionController::Caching
11
+
12
+ self.page_cache_directory = FILE_STORE_PATH
13
+ self.cache_store = :file_store, FILE_STORE_PATH
14
+ end
15
+
16
+ class PageCachingMetalTestController < CachingMetalController
17
+ caches_page :ok
18
+
19
+ def ok
20
+ self.response_body = 'ok'
21
+ end
22
+ end
23
+
24
+ class PageCachingMetalTest < ActionController::TestCase
25
+ tests PageCachingMetalTestController
26
+
27
+ def setup
28
+ super
29
+
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))
36
+ end
37
+
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'
42
+ end
43
+ end
44
+
45
+ ActionController::Base.page_cache_directory = FILE_STORE_PATH
46
+
47
+ class CachingController < ActionController::Base
48
+ abstract!
49
+
50
+ self.cache_store = :file_store, FILE_STORE_PATH
51
+ end
52
+
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
+ end
112
+
113
+ class PageCachingTest < ActionController::TestCase
114
+ def setup
115
+ super
116
+
117
+ @request = ActionController::TestRequest.new
118
+ @request.host = 'hostname.com'
119
+ @request.env.delete('PATH_INFO')
120
+
121
+ @controller = PageCachingTestController.new
122
+ @controller.perform_caching = true
123
+ @controller.cache_store = :file_store, FILE_STORE_PATH
124
+
125
+ @response = ActionController::TestResponse.new
126
+
127
+ @params = { controller: 'posts', action: 'index', only_path: true }
128
+
129
+ FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
130
+ FileUtils.mkdir_p(FILE_STORE_PATH)
131
+ end
132
+
133
+ def teardown
134
+ FileUtils.rm_rf(File.dirname(FILE_STORE_PATH))
135
+ @controller.perform_caching = false
136
+ end
137
+
138
+ def test_page_caching_resources_saves_to_correct_path_with_extension_even_if_default_route
139
+ with_routing do |set|
140
+ set.draw do
141
+ get 'posts.:format', to: 'posts#index', as: :formatted_posts
142
+ get '/', to: 'posts#index', as: :main
143
+ end
144
+ @params[:format] = 'rss'
145
+ assert_equal '/posts.rss', @routes.url_for(@params)
146
+ @params[:format] = nil
147
+ assert_equal '/', @routes.url_for(@params)
148
+ end
149
+ end
150
+
151
+ def test_should_cache_head_with_ok_status
152
+ head :ok
153
+ assert_response :ok
154
+ assert_page_cached :ok, 'head with ok status should have been cached'
155
+ end
156
+
157
+ def test_should_cache_get_with_ok_status
158
+ get :ok
159
+ assert_response :ok
160
+ assert_page_cached :ok, 'get with ok status should have been cached'
161
+ end
162
+
163
+ def test_should_cache_with_custom_path
164
+ get :custom_path
165
+ assert File.exist?("#{FILE_STORE_PATH}/index.html")
166
+ end
167
+
168
+ def test_should_expire_cache_with_custom_path
169
+ get :custom_path
170
+ assert File.exist?("#{FILE_STORE_PATH}/index.html")
171
+
172
+ get :expire_custom_path
173
+ assert !File.exist?("#{FILE_STORE_PATH}/index.html")
174
+ end
175
+
176
+ def test_should_gzip_cache
177
+ get :custom_path
178
+ assert File.exist?("#{FILE_STORE_PATH}/index.html.gz")
179
+
180
+ get :expire_custom_path
181
+ assert !File.exist?("#{FILE_STORE_PATH}/index.html.gz")
182
+ end
183
+
184
+ def test_should_allow_to_disable_gzip
185
+ get :no_gzip
186
+ assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/no_gzip.html")
187
+ assert !File.exist?("#{FILE_STORE_PATH}/page_caching_test/no_gzip.html.gz")
188
+ end
189
+
190
+ def test_should_use_config_gzip_by_default
191
+ @controller.expects(:cache_page).with(nil, nil, Zlib::BEST_COMPRESSION)
192
+ get :default_gzip
193
+ end
194
+
195
+ def test_should_set_gzip_level
196
+ @controller.expects(:cache_page).with(nil, nil, Zlib::BEST_SPEED)
197
+ get :gzip_level
198
+ end
199
+
200
+ def test_should_cache_without_trailing_slash_on_url
201
+ @controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash'
202
+ assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html")
203
+ end
204
+
205
+ def test_should_obey_http_accept_attribute
206
+ @request.env['HTTP_ACCEPT'] = 'text/xml'
207
+ get :about_me
208
+ assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/about_me.xml")
209
+ assert_equal 'I am xml', @response.body
210
+ end
211
+
212
+ def test_cached_page_should_not_have_trailing_slash_even_if_url_has_trailing_slash
213
+ @controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash/'
214
+ assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html")
215
+ end
216
+
217
+ def test_should_cache_ok_at_custom_path
218
+ @request.env['PATH_INFO'] = '/index.html'
219
+ get :ok
220
+ assert_response :ok
221
+ assert File.exist?("#{FILE_STORE_PATH}/index.html")
222
+ end
223
+
224
+ [:ok, :no_content, :found, :not_found].each do |status|
225
+ [:get, :post, :patch, :put, :delete].each do |method|
226
+ unless method == :get && status == :ok
227
+ define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do
228
+ send(method, status)
229
+ assert_response status
230
+ assert_page_not_cached status, "#{method} with #{status} status shouldn't have been cached"
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ def test_page_caching_conditional_options
237
+ get :ok, format: 'json'
238
+ assert_page_not_cached :ok
239
+ end
240
+
241
+ def test_page_caching_directory_set_as_pathname
242
+ begin
243
+ ActionController::Base.page_cache_directory = Pathname.new(FILE_STORE_PATH)
244
+ get :ok
245
+ assert_response :ok
246
+ assert_page_cached :ok
247
+ ensure
248
+ ActionController::Base.page_cache_directory = FILE_STORE_PATH
249
+ end
250
+ end
251
+
252
+ private
253
+
254
+ def assert_page_cached(action, message = "#{action} should have been cached")
255
+ assert page_cached?(action), message
256
+ end
257
+
258
+ def assert_page_not_cached(action, message = "#{action} shouldn't have been cached")
259
+ assert !page_cached?(action), message
260
+ end
261
+
262
+ def page_cached?(action)
263
+ File.exist? "#{FILE_STORE_PATH}/page_caching_test/#{action}.html"
264
+ end
265
+ end
@@ -0,0 +1,54 @@
1
+ require 'abstract_unit'
2
+ require 'active_support/log_subscriber/test_helper'
3
+ require 'action_controller/log_subscriber'
4
+
5
+ module Another
6
+ class LogSubscribersController < ActionController::Base
7
+ abstract!
8
+
9
+ self.perform_caching = true
10
+
11
+ def with_page_cache
12
+ cache_page('Super soaker', '/index.html')
13
+ render nothing: true
14
+ end
15
+ end
16
+ end
17
+
18
+ class ACLogSubscriberTest < ActionController::TestCase
19
+ tests Another::LogSubscribersController
20
+ include ActiveSupport::LogSubscriber::TestHelper
21
+
22
+ def setup
23
+ super
24
+
25
+ @routes = SharedTestRoutes
26
+ @routes.draw do
27
+ get ':controller(/:action)'
28
+ end
29
+
30
+ @cache_path = File.expand_path('../temp/test_cache', File.dirname(__FILE__))
31
+ ActionController::Base.page_cache_directory = @cache_path
32
+ @controller.cache_store = :file_store, @cache_path
33
+ ActionController::LogSubscriber.attach_to :action_controller
34
+ end
35
+
36
+ def teardown
37
+ ActiveSupport::LogSubscriber.log_subscribers.clear
38
+ FileUtils.rm_rf(@cache_path)
39
+ end
40
+
41
+ def set_logger(logger)
42
+ ActionController::Base.logger = logger
43
+ end
44
+
45
+ def test_with_page_cache
46
+ get :with_page_cache
47
+ wait
48
+
49
+ logs = @logger.logged(:info)
50
+ assert_equal 3, logs.size
51
+ assert_match(/Write page/, logs[1])
52
+ assert_match(/\/index\.html/, logs[1])
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: actionpack-page_caching
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - David Heinemeier Hansson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: actionpack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 4.0.0.beta
22
+ - - <
23
+ - !ruby/object:Gem::Version
24
+ version: '5.0'
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 4.0.0.beta
33
+ - - <
34
+ - !ruby/object:Gem::Version
35
+ version: '5.0'
36
+ - !ruby/object:Gem::Dependency
37
+ name: mocha
38
+ requirement: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ description: Static page caching for Action Pack (removed from core in Rails 4.0)
53
+ email: david@loudthinking.com
54
+ executables: []
55
+ extensions: []
56
+ extra_rdoc_files: []
57
+ files:
58
+ - .gitignore
59
+ - .travis.yml
60
+ - Gemfile
61
+ - LICENSE.txt
62
+ - README.md
63
+ - Rakefile
64
+ - actionpack-page_caching.gemspec
65
+ - lib/action_controller/caching/pages.rb
66
+ - lib/action_controller/page_caching.rb
67
+ - lib/actionpack/page_caching.rb
68
+ - test/abstract_unit.rb
69
+ - test/caching_test.rb
70
+ - test/log_subscriber_test.rb
71
+ homepage: https://github.com/rails/actionpack-page_caching
72
+ licenses: []
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ segments:
84
+ - 0
85
+ hash: -3221289291449312417
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ segments:
93
+ - 0
94
+ hash: -3221289291449312417
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 1.8.23
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: Static page caching for Action Pack (removed from core in Rails 4.0)
101
+ test_files:
102
+ - test/abstract_unit.rb
103
+ - test/caching_test.rb
104
+ - test/log_subscriber_test.rb