josevalim-easy_http_cache 2.0 → 2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +73 -47
- data/Rakefile +9 -2
- data/lib/easy_http_cache.rb +2 -18
- data/test/easy_http_cache_test.rb +13 -40
- metadata +2 -3
- data/init.rb +0 -1
data/README
CHANGED
@@ -1,21 +1,11 @@
|
|
1
|
-
|
2
|
-
Site: http://www.pagestacker.com/
|
3
|
-
Blog: http://josevalim.blogspot.com/
|
1
|
+
Easy HTTP Cache
|
4
2
|
License: MIT
|
5
|
-
Version: 2.
|
3
|
+
Version: 2.1
|
6
4
|
|
7
5
|
You can also read this README in pretty html at the GitHub project Wiki page
|
8
6
|
|
9
7
|
http://github.com/josevalim/easy_http_cache/wikis/home
|
10
8
|
|
11
|
-
Warning
|
12
|
-
-------
|
13
|
-
|
14
|
-
Since version 2.0, this plugin/gem has drastically changed to fit Rails 2.2
|
15
|
-
http cache goodness. :expires_in, :expires_at and :control options were
|
16
|
-
removed, so if you want to use previous versions, see "Previous versions"
|
17
|
-
below.
|
18
|
-
|
19
9
|
Description
|
20
10
|
-----------
|
21
11
|
|
@@ -23,36 +13,42 @@ Allows Rails applications to do conditional cache easily and in a DRY way
|
|
23
13
|
(without messing up your actions):
|
24
14
|
|
25
15
|
class ListsController < ApplicationController
|
26
|
-
http_cache :index, :show
|
16
|
+
http_cache :index, :show, :last_modified => :list
|
17
|
+
|
18
|
+
protected
|
19
|
+
def list
|
20
|
+
@list ||= List.find(params[:id])
|
21
|
+
end
|
27
22
|
end
|
28
23
|
|
29
24
|
It uses :last_modified and :etag keys, that besides Time, String or resources
|
30
|
-
accepts Proc, Method and
|
31
|
-
|
25
|
+
accepts Proc, Method and Symbol that are evaluated within the current controller.
|
26
|
+
|
27
|
+
Read more about each option (more examples at the end of this page):
|
32
28
|
|
33
29
|
:last_modified
|
34
30
|
Used to manipulate Last-Modified header. You can pass any object that responds
|
35
|
-
to :to_time. If you pass a Proc or Method or
|
36
|
-
within the current controller
|
31
|
+
to :updated_at, :updated_on or :to_time. If you pass a Proc or Method or Symbol,
|
32
|
+
they will be evaluated within the current controller first.
|
37
33
|
|
38
|
-
|
39
|
-
it. If you want to call a different method on your resource, you can pass it as
|
40
|
-
a symbol using the :method option.
|
41
|
-
|
42
|
-
All times will be converted to UTC. Finally, if you pass an array, it will get
|
43
|
-
the most recent time to be used.
|
34
|
+
Finally, if you pass an array, it will get the most recent time to be used.
|
44
35
|
|
45
36
|
:etag
|
46
|
-
Used to manipulate Etag header.
|
47
|
-
|
48
|
-
|
49
|
-
|
37
|
+
Used to manipulate Etag header. The Etag is generated as memcached keys are
|
38
|
+
generated, i.e. calling to_param in the object and then MD5 is applied.
|
39
|
+
|
40
|
+
If you pass a Proc or Method or Symbols, they will be also evaluated within the
|
41
|
+
current controller first.
|
50
42
|
|
51
43
|
:if
|
52
44
|
Only perform http cache if it returns true.
|
53
45
|
|
54
46
|
:unless
|
55
47
|
Only perform http cache if it returns false.
|
48
|
+
|
49
|
+
:method
|
50
|
+
If in :last_modified you want to pass a object that doesn't respond to updated_at,
|
51
|
+
updated_on or to_time, you can specify the method that will be called in this object.
|
56
52
|
|
57
53
|
|
58
54
|
Install
|
@@ -62,9 +58,6 @@ Install Easy HTTP Cache is very easy. It is stored in GitHub, so if you
|
|
62
58
|
have never installed a gem via GitHub run the following:
|
63
59
|
|
64
60
|
gem sources -a http://gems.github.com
|
65
|
-
|
66
|
-
Then install the gem:
|
67
|
-
|
68
61
|
sudo gem install josevalim-easy_http_cache
|
69
62
|
|
70
63
|
In RAILS_ROOT/config/environment.rb:
|
@@ -77,6 +70,7 @@ If you want it as plugin, just do:
|
|
77
70
|
git clone git://github.com/josevalim/easy_http_cache.git
|
78
71
|
rm -rf vendor/plugins/easy_http_cache/.git
|
79
72
|
|
73
|
+
Current version supports Rails 2.2.x and Rails 2.3.x.
|
80
74
|
|
81
75
|
Previous versions
|
82
76
|
-----------------
|
@@ -89,21 +83,21 @@ If you are running on Rails 2.1.x, you should use v1.2.3:
|
|
89
83
|
git checkout v1.2.3
|
90
84
|
rm -rf ./.git
|
91
85
|
|
92
|
-
If you are using
|
86
|
+
If you are using earlier than 2.1, please upgrade your app. =)
|
93
87
|
|
94
88
|
|
95
89
|
Variables
|
96
90
|
---------
|
97
91
|
|
98
|
-
|
99
|
-
the
|
100
|
-
|
92
|
+
As in memcached, you can set ENV['RAILS_CACHE_ID'] or ENV['RAILS_APP_VERSION'] variables
|
93
|
+
to change the Etag that will be generated. This means you can control the cache by setting
|
94
|
+
a timestamp or a version number in ENV['RAILS_APP_VERSION'] everytime you deploy.
|
101
95
|
|
102
96
|
|
103
97
|
Examples
|
104
98
|
--------
|
105
99
|
|
106
|
-
|
100
|
+
The example below will cache your actions and it will never expire:
|
107
101
|
|
108
102
|
class ListsController < ApplicationController
|
109
103
|
http_cache :index, :show
|
@@ -113,10 +107,10 @@ If you do not want to cache when you are showing a flash message (and you
|
|
113
107
|
usually want that), you can simply do:
|
114
108
|
|
115
109
|
class ListsController < ApplicationController
|
116
|
-
http_cache :index, :show, :if => Proc.new { |c| c.
|
110
|
+
http_cache :index, :show, :if => Proc.new { |c| c.send(:flash).empty? }
|
117
111
|
end
|
118
112
|
|
119
|
-
And if you do not want JSON requests:
|
113
|
+
And if you do not want to cache JSON requests:
|
120
114
|
|
121
115
|
class ListsController < ApplicationController
|
122
116
|
http_cache :index, :show, :unless => Proc.new { |c| c.request.format.json? }
|
@@ -128,8 +122,8 @@ Or if you want to expire all http cache before 2008, just do:
|
|
128
122
|
http_cache :index, :show, :last_modified => Time.utc(2008)
|
129
123
|
end
|
130
124
|
|
131
|
-
If
|
132
|
-
it
|
125
|
+
If you want to cache a list and automatically expire the cache when it changes,
|
126
|
+
just do (it will check updated_at and updated_on on the @list object):
|
133
127
|
|
134
128
|
class ListsController < ApplicationController
|
135
129
|
http_cache :index, :show, :last_modified => :list
|
@@ -140,7 +134,8 @@ it changes, just do:
|
|
140
134
|
end
|
141
135
|
end
|
142
136
|
|
143
|
-
You can also set :etag header
|
137
|
+
You can also set :etag header (it will generate an etag calling to_param
|
138
|
+
in the object and applying MD5):
|
144
139
|
|
145
140
|
class ListsController < ApplicationController
|
146
141
|
http_cache :index, :show, :etag => :list
|
@@ -152,23 +147,54 @@ You can also set :etag header:
|
|
152
147
|
end
|
153
148
|
|
154
149
|
If you are using a resource that doesn't respond to updated_at or updated_on,
|
155
|
-
you can pass a method as parameter
|
150
|
+
you can pass a method as parameter that will be called in your resources:
|
156
151
|
|
157
152
|
class ListsController < ApplicationController
|
158
153
|
http_cache :index, :show, :last_modified => :list, :method => :cached_at
|
159
154
|
|
160
155
|
protected
|
161
|
-
|
162
|
-
|
163
|
-
|
156
|
+
def list
|
157
|
+
@list ||= List.find(params[:id])
|
158
|
+
end
|
164
159
|
end
|
165
160
|
|
161
|
+
The sample below will call @list.cached_at to generate Last-Modified header.
|
166
162
|
Finally, you can also pass an array at :last_modified as below:
|
167
163
|
|
168
|
-
class
|
164
|
+
class ItemsController < ApplicationController
|
169
165
|
http_cache :index, :show,
|
170
|
-
:last_modified => [ :list,
|
166
|
+
:last_modified => [ :list, :item ]
|
167
|
+
|
168
|
+
protected
|
169
|
+
def list
|
170
|
+
@list ||= List.find(params[:list_id])
|
171
|
+
end
|
172
|
+
|
173
|
+
def item
|
174
|
+
@item ||= list.items.find(params[:id])
|
175
|
+
end
|
171
176
|
end
|
172
177
|
|
173
178
|
This will check which one is the most recent to compare with the
|
174
|
-
"Last-Modified" field sent by the client.
|
179
|
+
"Last-Modified" field sent by the client.
|
180
|
+
|
181
|
+
|
182
|
+
What if?
|
183
|
+
--------
|
184
|
+
|
185
|
+
At this point (or at some point), you will ask what happens if you use :etag
|
186
|
+
and :last_modified at the same time.
|
187
|
+
|
188
|
+
Well, Padawan, the specification says that if both are sent by the client, both have
|
189
|
+
to be valid for the cache not be considered stale. This subject was already brought
|
190
|
+
to Rails Core group and this is also how Rails' current implementation behaves.
|
191
|
+
|
192
|
+
Bugs and Feedback
|
193
|
+
-----------------
|
194
|
+
|
195
|
+
If you discover any bugs, please send an e-mail to jose.valim@gmail.com
|
196
|
+
If you just want to give some positive feedback or drop a line, that's fine too! =)
|
197
|
+
|
198
|
+
Copyright (c) 2009 José Valim
|
199
|
+
http://www.pagestacker.com/
|
200
|
+
http://josevalim.blogspot.com/
|
data/Rakefile
CHANGED
@@ -2,11 +2,18 @@ require 'rake'
|
|
2
2
|
require 'rake/testtask'
|
3
3
|
require 'rake/rdoctask'
|
4
4
|
|
5
|
-
desc '
|
5
|
+
desc 'Run tests for Easy HTTP Cache.'
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.pattern = 'test/**/*_test.rb'
|
8
|
+
t.verbose = true
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'Generate documentation for Easy HTTP Cache.'
|
6
12
|
Rake::RDocTask.new(:rdoc) do |rdoc|
|
7
13
|
rdoc.rdoc_dir = 'rdoc'
|
8
14
|
rdoc.title = 'Easy HTTP Cache'
|
9
15
|
rdoc.options << '--line-numbers' << '--inline-source'
|
10
16
|
rdoc.rdoc_files.include('README')
|
17
|
+
rdoc.rdoc_files.include('MIT-LICENSE')
|
11
18
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
12
|
-
end
|
19
|
+
end
|
data/lib/easy_http_cache.rb
CHANGED
@@ -33,10 +33,6 @@ module ActionController #:nodoc:
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def filter(controller)
|
36
|
-
# We don't go ahead if we are rendering a component
|
37
|
-
#
|
38
|
-
return if component_request?(controller)
|
39
|
-
|
40
36
|
last_modified = get_last_modified(controller)
|
41
37
|
controller.response.last_modified = last_modified if last_modified
|
42
38
|
|
@@ -44,7 +40,7 @@ module ActionController #:nodoc:
|
|
44
40
|
controller.response.etag = processed_etags if processed_etags
|
45
41
|
|
46
42
|
if controller.request.fresh?(controller.response)
|
47
|
-
controller.
|
43
|
+
controller.send(:head, :not_modified)
|
48
44
|
return false
|
49
45
|
end
|
50
46
|
end
|
@@ -53,11 +49,6 @@ module ActionController #:nodoc:
|
|
53
49
|
# If :etag is an array, it processes all Methods, Procs and Symbols
|
54
50
|
# and return them as array. If it's an object, we only evaluate it.
|
55
51
|
#
|
56
|
-
# Finally, if :etag is not sent but RAILS_CACHE_ID or RAILS_APP_VERSION
|
57
|
-
# are set, we return an empty string allowing etag to be performed
|
58
|
-
# because those variables, when modified, are a valid way to expire
|
59
|
-
# all previous caches.
|
60
|
-
#
|
61
52
|
def get_processed_etags(controller)
|
62
53
|
if @options[:etag].is_a?(Array)
|
63
54
|
@options[:etag].collect do |item|
|
@@ -65,8 +56,6 @@ module ActionController #:nodoc:
|
|
65
56
|
end
|
66
57
|
elsif @options[:etag]
|
67
58
|
evaluate_method(@options[:etag], controller)
|
68
|
-
elsif ENV['RAILS_CACHE_ID'] || ENV['RAILS_APP_VERSION']
|
69
|
-
''
|
70
59
|
else
|
71
60
|
nil
|
72
61
|
end
|
@@ -126,15 +115,10 @@ module ActionController #:nodoc:
|
|
126
115
|
end
|
127
116
|
end
|
128
117
|
|
129
|
-
# We should not do http cache when we are using components
|
130
|
-
#
|
131
|
-
def component_request?(controller)
|
132
|
-
controller.instance_variable_get('@parent_controller')
|
133
|
-
end
|
134
118
|
end
|
135
119
|
|
136
120
|
end
|
137
121
|
end
|
138
122
|
end
|
139
123
|
|
140
|
-
ActionController::Base.
|
124
|
+
ActionController::Base.send :include, ActionController::Caching::HttpCache
|
@@ -1,9 +1,16 @@
|
|
1
1
|
# Those lines are plugin test settings
|
2
|
-
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rubygems'
|
3
4
|
require 'ostruct'
|
4
|
-
|
5
|
+
|
6
|
+
ENV["RAILS_ENV"] = "test"
|
7
|
+
|
8
|
+
require 'active_support'
|
9
|
+
require 'action_controller'
|
10
|
+
require 'action_controller/test_case'
|
11
|
+
require 'action_controller/test_process'
|
12
|
+
|
5
13
|
require File.dirname(__FILE__) + '/../lib/easy_http_cache.rb'
|
6
|
-
require 'test_help'
|
7
14
|
|
8
15
|
ActionController::Base.perform_caching = true
|
9
16
|
ActionController::Routing::Routes.draw do |map|
|
@@ -62,7 +69,7 @@ class HttpCacheTestController < ActionController::Base
|
|
62
69
|
end
|
63
70
|
end
|
64
71
|
|
65
|
-
class HttpCacheTest <
|
72
|
+
class HttpCacheTest < ActionController::TestCase
|
66
73
|
def setup
|
67
74
|
reset!
|
68
75
|
end
|
@@ -115,17 +122,7 @@ class HttpCacheTest < Test::Unit::TestCase
|
|
115
122
|
@request.env['HTTP_ACCEPT'] = 'application/json'
|
116
123
|
@request.env['HTTP_IF_MODIFIED_SINCE'] = 1.hour.ago.httpdate
|
117
124
|
get :show
|
118
|
-
assert_equal '200 OK', @response.
|
119
|
-
end
|
120
|
-
|
121
|
-
def test_http_cache_without_input_with_env_variable
|
122
|
-
ENV['RAILS_APP_VERSION'] = '1.2.3'
|
123
|
-
|
124
|
-
get :index
|
125
|
-
assert_headers('200 OK', 'private, max-age=0, must-revalidate', 'Last-Modified', Time.utc(0).httpdate)
|
126
|
-
reset!
|
127
|
-
|
128
|
-
etag_http_cache(:index, '')
|
125
|
+
assert_equal '200 OK', @response.status
|
129
126
|
end
|
130
127
|
|
131
128
|
def test_etag_http_cache
|
@@ -141,22 +138,6 @@ class HttpCacheTest < Test::Unit::TestCase
|
|
141
138
|
etag_http_cache(:etag, 'ETAG_CACHE')
|
142
139
|
end
|
143
140
|
|
144
|
-
def test_should_not_cache_when_rendering_components
|
145
|
-
set_parent_controller!
|
146
|
-
get :show
|
147
|
-
assert_headers('200 OK', 'no-cache')
|
148
|
-
|
149
|
-
set_parent_controller!
|
150
|
-
@request.env['HTTP_IF_MODIFIED_SINCE'] = 1.hour.ago.httpdate
|
151
|
-
get :show
|
152
|
-
assert_headers('200 OK', 'no-cache')
|
153
|
-
|
154
|
-
set_parent_controller!
|
155
|
-
@request.env['HTTP_IF_MODIFIED_SINCE'] = 3.hours.ago.httpdate
|
156
|
-
get :show
|
157
|
-
assert_headers('200 OK', 'no-cache')
|
158
|
-
end
|
159
|
-
|
160
141
|
private
|
161
142
|
def reset!
|
162
143
|
@request = ActionController::TestRequest.new
|
@@ -164,20 +145,12 @@ class HttpCacheTest < Test::Unit::TestCase
|
|
164
145
|
@controller = HttpCacheTestController.new
|
165
146
|
end
|
166
147
|
|
167
|
-
def set_parent_controller!
|
168
|
-
get :index
|
169
|
-
old_controller = @controller.dup
|
170
|
-
reset!
|
171
|
-
|
172
|
-
@controller.instance_variable_set('@parent_controller', old_controller)
|
173
|
-
end
|
174
|
-
|
175
148
|
def etag_for(etag)
|
176
149
|
%("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))}")
|
177
150
|
end
|
178
151
|
|
179
152
|
def assert_headers(status, control, cache_header=nil, value=nil)
|
180
|
-
assert_equal status, @response.
|
153
|
+
assert_equal status, @response.status
|
181
154
|
assert_equal control, @response.headers['Cache-Control']
|
182
155
|
|
183
156
|
if cache_header
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: josevalim-easy_http_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "2.
|
4
|
+
version: "2.1"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Jos\xC3\xA9 Valim"
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-02-04 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -25,7 +25,6 @@ files:
|
|
25
25
|
- MIT-LICENSE
|
26
26
|
- README
|
27
27
|
- Rakefile
|
28
|
-
- init.rb
|
29
28
|
- lib/easy_http_cache.rb
|
30
29
|
- test/easy_http_cache_test.rb
|
31
30
|
has_rdoc: true
|
data/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'easy_http_cache'
|