Module: Juicer::CacheBuster
- Defined in:
- lib/juicer/cache_buster.rb
Overview
Assists in creating filenames that reflect the last change to the file. These kinds of filenames are useful when serving static content through a web server. If the filename changes everytime the file is modified, you can safely configure the web server to cache files indefinately, and know that the updated filename will cause the file to be downloaded again - only once - when it has changed.
Types of cache busters
Query string / “soft” cache busters
Soft cache busters require no web server configuration. However, it is not guaranteed to work in all settings. For example, older default configurations for popular proxy server Squid does not consider a known URL with a new query string a new URL, and thus will not download the file over.
The soft cache busters transforms /images/logo.png
to /images/logo.png?cb=1232923789
Filename change / “hard” cache busters
Hard cache busters change the file name itself, and thus requires either the web server to (internally) rewrite requests for these files to the original ones, or the file names to actually change. Hard cache busters transforms /images/logo.png
to /images/logo-1232923789.png
Hard cache busters are guaranteed to work, and is the recommended variant. An example configuration for the Apache web server that does not require you to actually change the filenames can be seen below.
<VirtualHost *>
# Application/website configuration
# Cache static resources for a year
<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
ExpiresActive On
ExpiresDefault "access plus 1 year"
</FilesMatch>
# Rewrite URLs like /images/logo-cb1234567890.png to /images/logo.png
RewriteEngine On
RewriteRule (.*)-cb\d+\.(.*)$ $1.$2 [L]
</VirtualHost>])
Consecutive calls
Consecutive calls to add a cache buster to a path will replace the existing cache buster *as long as the parameter name is the same*. Consider this:
file = Juicer::CacheBuster.hard("/home/file.png") #=> "/home/file-cb1234567890.png"
Juicer::CacheBuster.hard(file) #=> "/home/file-cb1234567891.png"
# Changing the parameter name breaks this
Juicer::CacheBuster.hard(file, :juicer) #=> "/home/file-cb1234567891-juicer1234567892.png"
Avoid this type of trouble simply be cleaning the URL with the old name first:
Juicer::CacheBuster.clean(file) #=> "/home/file.png"
file = Juicer::CacheBuster.hard(file, :juicer) #=> "/home/file-juicer1234567892.png"
Juicer::CacheBuster.clean(file, :juicer) #=> "/home/file.png"
- Author
-
Christian Johansen ([email protected])
- Copyright
-
Copyright © 2009 Christian Johansen
- License
-
BSD
Defined Under Namespace
Modules: Revision
Constant Summary collapse
- DEFAULT_PARAMETER =
"jcb"
Class Method Summary collapse
-
.clean(file, parameter = DEFAULT_PARAMETER) ⇒ Object
Remove cache buster from a URL for a given parameter name.
-
.hard(file, opts = {}) ⇒ Object
Add a hard cache buster to a filename.
-
.path(file, opts = {}) ⇒ Object
Creates a unique file name for every revision to the files contents.
-
.rails(file, opts = {}) ⇒ Object
Add a Rails-style cache buster to a filename.
-
.soft(file, opts = {}) ⇒ Object
Add a soft cache buster to a filename.
Class Method Details
.clean(file, parameter = DEFAULT_PARAMETER) ⇒ Object
Remove cache buster from a URL for a given parameter name. Parameter name is “cb” by default.
146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/juicer/cache_buster.rb', line 146 def self.clean(file, parameter = DEFAULT_PARAMETER) if "#{parameter}".length == 0 return file.sub(/\?\d+$/, '') else query_param = "#{parameter}=" new_file = file.sub(/#{query_param}\d+&?/, "").sub(/(\?|&)$/, "") return new_file unless new_file == file file.sub(/-#{parameter}\d+(\.\w+)($|\?)/, '\1\2') end end |
.hard(file, opts = {}) ⇒ Object
Add a hard cache buster to a filename. The parameter is an optional prefix that is added before the mtime timestamp. It results in filenames of the form: file-[parameter name][timestamp].suffix
, ie images/logo-cb1234567890.png
which is the case for the default parameter name “cb” (as in *c*ache *b*uster).
118 119 120 |
# File 'lib/juicer/cache_buster.rb', line 118 def self.hard(file, opts = {}) self.path(file, opts.merge(:type => :hard)) end |
.path(file, opts = {}) ⇒ Object
Creates a unique file name for every revision to the files contents. Raises an ArgumentError
if the file can not be found.
The type indicates which type of cache buster you want, :soft
or :hard
. Default is :soft
. If an unsupported value is specified, :soft
will be used.
See #hard
and #soft
for explanation of the parameter argument.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/juicer/cache_buster.rb', line 81 def self.path(file, opts = {}) return file if file =~ /data:.*;base64/ type = opts[:type] type = [:soft, :hard, :rails].include?(type) ? type : :soft parameter = opts.key?(:parameter) ? opts[:parameter] : DEFAULT_PARAMETER parameter = nil if type == :rails file = self.clean(file, parameter) filename = file.split("?").first revision_type = opts[:revision_type] revision_type = :mtime if type == :rails revision_type = [:git, :mtime].include?(revision_type) ? revision_type : :mtime raise ArgumentError.new("#{file} could not be found") unless File.exists?(filename) revision = Revision.send(revision_type, filename) if type == :soft parameter = "#{parameter}=".sub(/^=$/, '') return "#{file}#{file.index('?') ? '&' : '?'}#{parameter}#{revision}" elsif type == :rails return "#{file}#{file.index('?') ? '' : "?#{revision}"}" end file.sub(/(\.[^\.]+$)/, "-#{parameter}#{revision}" + '\1') end |
.rails(file, opts = {}) ⇒ Object
Add a Rails-style cache buster to a filename. Results in filenames of the form: file.suffix?[timestamp]
, ie images/logo.png?1234567890
which is the format used by Rails’ image_tag helper.
138 139 140 |
# File 'lib/juicer/cache_buster.rb', line 138 def self.rails(file, opts = {}) self.path(file, opts.merge(:type => :rails)) end |
.soft(file, opts = {}) ⇒ Object
Add a soft cache buster to a filename. The parameter is an optional name for the mtime timestamp value. It results in filenames of the form: file.suffix?[parameter name]=[timestamp]
, ie images/logo.png?cb=1234567890
which is the case for the default parameter name “cb” (as in *c*ache *b*uster).
129 130 131 |
# File 'lib/juicer/cache_buster.rb', line 129 def self.soft(file, opts = {}) self.path(file, opts.merge(:type => :soft)) end |