aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
authorCraig R Webster <craig@barkingiguana.com>2010-03-21 19:35:38 +0000
committerwycats <wycats@gmail.com>2010-03-28 18:35:05 -0700
commit49bc6a249e2a200216f8a96c36093a2c7a471c9b (patch)
treeb699e8c5780a7ca92f11af16cc1945837302b6a3 /actionpack
parentcf6734fdf9d72bfc7fe92e36bf603d67ad815e6b (diff)
downloadrails-49bc6a249e2a200216f8a96c36093a2c7a471c9b.tar.gz
rails-49bc6a249e2a200216f8a96c36093a2c7a471c9b.tar.bz2
rails-49bc6a249e2a200216f8a96c36093a2c7a471c9b.zip
Allow customisation of asset path generation using a proc.
Set config.action_controller.asset_path_template to a proc that takes one argument - the direct, unchanged asset path - and returns a path to that asset using the scheme that your assets require. This is useful if you have a setup which scales by introducing new application servers where the mtime of the asset files may not be the same as those of the asset files on your previous servers, but it does require your web servers to have knowledge of the asset template paths that you rewrite to so it's not suitable for out-of-the-box use. An example of configuring asset path generation and rewriting these paths using Apache is included in actionpack/lib/action_view/helpers/asset_tag_helper.rb. Signed-off-by: wycats <wycats@gmail.com>
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb68
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb9
2 files changed, 75 insertions, 2 deletions
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 02ad41719b..635c58bc35 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -108,7 +108,7 @@ module ActionView
# "http://asset%d.example.com", "https://asset1.example.com"
# )
#
- # === Using asset timestamps
+ # === Using asset path templates
#
# By default, Rails appends asset's timestamps to all asset paths. This allows
# you to set a cache-expiration date for the asset far into the future, but
@@ -133,6 +133,65 @@ module ActionView
# will request the same assets over and over again even thought they didn't
# change. You can use something like Live HTTP Headers for Firefox to verify
# that the cache is indeed working.
+ #
+ # This strategy works well enough for most server setups and requires the
+ # least configuration, but if you deploy several application servers at
+ # different times - say to handle a temporary spike in load - then the
+ # asset time stamps will be out of sync. In a setup like this you may want
+ # to set the way that asset paths are generated yourself.
+ #
+ # Altering the asset paths that Rails generates can be done in two ways.
+ # The easiest is to define the RAILS_ASSET_ID environment variable. The
+ # contents of this variable will always be used in preference to
+ # calculated timestamps. A more complex but flexible way is to set
+ # <tt>ActionController::Base.config.asset_path_template</tt> to a proc
+ # that takes the unmodified asset path and returns the path needed for
+ # your asset caching to work. Typically you'd do something like this in
+ # <tt>config/environments/production.rb</tt>:
+ #
+ # # Normally you'd calculate RELEASE_NUMBER at startup.
+ # RELEASE_NUMBER = 12345
+ # config.action_controller.asset_path_template = proc { |asset_path|
+ # "/release-#{RELEASE_NUMBER}#{asset_path}"
+ # }
+ #
+ # This example would cause the following behaviour on all servers no
+ # matter when they were deployed:
+ #
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="/release-12345/images/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="/release-12345/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />
+ #
+ # Changing the asset_path_template does require that your web servers have
+ # knowledge of the asset template paths that you rewrite to so it's not
+ # suitable for out-of-the-box use. To use the example given above you
+ # could use something like this in your Apache VirtualHost configuration:
+ #
+ # <LocationMatch "^/release-\d+/(images|javascripts|stylesheets)/.*$">
+ # # Some browsers still send conditional-GET requests if there's a
+ # # Last-Modified header or an ETag header even if they haven't
+ # # reached the expiry date sent in the Expires header.
+ # Header unset Last-Modified
+ # Header unset ETag
+ # FileETag None
+ #
+ # # Assets requested using a cache-busting filename should be served
+ # # only once and then cached for a really long time. The HTTP/1.1
+ # # spec frowns on hugely-long expiration times though and suggests
+ # # that assets which never expire be served with an expiration date
+ # # 1 year from access.
+ # ExpiresActive On
+ # ExpiresDefault "access plus 1 year"
+ # </LocationMatch>
+ #
+ # # We use cached-busting location names with the far-future expires
+ # # headers to ensure that if a file does change it can force a new
+ # # request. The actual asset filenames are still the same though so we
+ # # need to rewrite the location from the cache-busting location to the
+ # # real asset location so that we can serve it.
+ # RewriteEngine On
+ # RewriteRule ^/release-\d+/(images|javascripts|stylesheets)/(.*)$ /$1/$2 [L]
module AssetTagHelper
JAVASCRIPT_DEFAULT_SOURCES = ['prototype', 'effects', 'dragdrop', 'controls', 'rails'].freeze unless const_defined?(:JAVASCRIPT_DEFAULT_SOURCES)
@@ -646,7 +705,12 @@ module ActionView
source += ".#{ext}" if rewrite_extension?(source, dir, ext)
source = "/#{dir}/#{source}" unless source[0] == ?/
- source = rewrite_asset_path(source)
+ asset_path_template = config.asset_path_template
+ if asset_path_template && asset_path_template.respond_to?(:call)
+ source = asset_path_template.call(source)
+ else
+ source = rewrite_asset_path(source)
+ end
has_request = controller.respond_to?(:request)
if has_request && include_host && source !~ %r{^#{controller.config.relative_url_root}/}
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index c471df861d..43d11df8fe 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -373,6 +373,15 @@ class AssetTagHelperTest < ActionView::TestCase
assert_equal %(<img alt="Rails" src="/images/rails.png?#{expected_time}" />), image_tag("rails.png")
end
+ def test_proc_asset_id
+ @controller.config.asset_path_template = Proc.new do |asset_path|
+ "/assets.v12345#{asset_path}"
+ end
+
+ expected_path = "/assets.v12345/images/rails.png"
+ assert_equal %(<img alt="Rails" src="#{expected_path}" />), image_tag("rails.png")
+ end
+
def test_timebased_asset_id_with_relative_url_root
@controller.config.relative_url_root = "/collaboration/hieraki"
expected_time = File.stat(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).mtime.to_i.to_s