From 266b80c7b28c7587ab1c75aae6e3288e2f6c1aba Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Mon, 13 Jun 2011 22:45:34 -0700 Subject: OrderedOptions must implement respond_to? if it implements method_missing. --- activesupport/lib/active_support/ordered_options.rb | 4 ++++ railties/lib/rails/engine.rb | 12 +++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb index 8d8e6ebc58..bf81567d22 100644 --- a/activesupport/lib/active_support/ordered_options.rb +++ b/activesupport/lib/active_support/ordered_options.rb @@ -36,6 +36,10 @@ module ActiveSupport #:nodoc: self[name] end end + + def respond_to?(name) + true + end end class InheritableOptions < OrderedOptions diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 52c89274e7..bf57a034b2 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -538,15 +538,9 @@ module Rails end initializer :append_assets_path do |app| - if app.config.assets.respond_to?(:prepend_path) - app.config.assets.prepend_path(*paths["vendor/assets"].existent) - app.config.assets.prepend_path(*paths["lib/assets"].existent) - app.config.assets.prepend_path(*paths["app/assets"].existent) - else - app.config.assets.paths.unshift(*paths["vendor/assets"].existent) - app.config.assets.paths.unshift(*paths["lib/assets"].existent) - app.config.assets.paths.unshift(*paths["app/assets"].existent) - end + app.config.assets.paths.unshift(*paths["vendor/assets"].existent) + app.config.assets.paths.unshift(*paths["lib/assets"].existent) + app.config.assets.paths.unshift(*paths["app/assets"].existent) end initializer :prepend_helpers_path do |app| -- cgit v1.2.3 From 96137e8bd0a0094d26cc0cf6f86642487a60735f Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Mon, 27 Jun 2011 13:48:36 -0700 Subject: Add asset_url helper and refactor the asset paths so that asset hosts can be used during asset precompilation. Conflicts: actionpack/lib/action_view/asset_paths.rb actionpack/lib/sprockets/helpers/rails_helper.rb actionpack/test/template/sprockets_helper_test.rb --- actionpack/lib/action_view/asset_paths.rb | 72 ++++++++++++++++------ .../helpers/asset_tag_helpers/asset_include_tag.rb | 23 ++++--- actionpack/lib/sprockets/helpers/rails_helper.rb | 19 +++--- actionpack/test/template/asset_tag_helper_test.rb | 8 +-- actionpack/test/template/sprockets_helper_test.rb | 54 ++++++++++++++-- 5 files changed, 129 insertions(+), 47 deletions(-) diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb index 2b1fe545a6..4974bd5426 100644 --- a/actionpack/lib/action_view/asset_paths.rb +++ b/actionpack/lib/action_view/asset_paths.rb @@ -4,7 +4,7 @@ module ActionView class AssetPaths #:nodoc: attr_reader :config, :controller - def initialize(config, controller) + def initialize(config, controller = nil) @config = config @controller = controller end @@ -19,15 +19,17 @@ module ActionView source = rewrite_extension(source, dir, ext) if ext source = rewrite_asset_path(source, dir) - - if controller && include_host - has_request = controller.respond_to?(:request) - source = rewrite_host_and_protocol(source, has_request) - end - + source = rewrite_relative_url_root(source, relative_url_root) if has_request? + source = rewrite_host_and_protocol(source) if include_host source end + # Return the filesystem path for the source + def compute_source_path(source, dir, ext) + source = rewrite_extension(source, dir, ext) if ext + File.join(config.assets_dir, dir, source) + end + def is_uri?(path) path =~ %r{^[-a-z]+://|^cid:|^//} end @@ -46,13 +48,14 @@ module ActionView relative_url_root && !source.starts_with?("#{relative_url_root}/") ? "#{relative_url_root}#{source}" : source end - def rewrite_host_and_protocol(source, has_request) - source = rewrite_relative_url_root(source, controller.config.relative_url_root) if has_request + def has_request? + controller.respond_to?(:request) + end + + def rewrite_host_and_protocol(source) host = compute_asset_host(source) - if has_request && host && !is_uri?(host) - host = "#{controller.request.protocol}#{host}" - end - "#{host}#{source}" + host = "//#{host}" if host && !is_uri?(host) + host.nil? ? source : "#{host}#{source}" end # Pick an asset host for this source. Returns +nil+ if no host is set, @@ -61,19 +64,48 @@ module ActionView # or the value returned from invoking call on an object responding to call # (proc or otherwise). def compute_asset_host(source) - if host = config.asset_host + if host = asset_host_config if host.respond_to?(:call) - case host.is_a?(Proc) ? host.arity : host.method(:call).arity - when 2 - request = controller.respond_to?(:request) && controller.request - host.call(source, request) - else - host.call(source) + args = [source] + arity = arity_of(host) + if arity > 1 && !has_request? + raise ActionController::RoutingError, "This asset host cannot be computed without a request in scope. Remove the second argument to your asset_host Proc if you do not need the request." end + args << current_request if (arity > 1 || arity < 0) && has_request? + host.call(*args) else (host =~ /%d/) ? host % (source.hash % 4) : host end end end + + def relative_url_root + if controller.respond_to?(:config) && controller.config + controller.config.relative_url_root + elsif config.respond_to?(:action_controller) && config.action_controller + config.action_controller.relative_url_root + elsif Rails.respond_to?(:application) && Rails.application.config + Rails.application.config.action_controller.relative_url_root + end + end + + def asset_host_config + if config.respond_to?(:asset_host) + config.asset_host + elsif Rails.respond_to?(:application) + Rails.application.config.action_controller.asset_host + end + end + + # Returns the current request if one exists. + def current_request + controller.request if has_request? + end + + # Returns the arity of a callable + def arity_of(callable) + callable.respond_to?(:arity) ? callable.arity : callable.method(:call).arity + end + end end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb index e4662a2919..16d8f3f893 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb @@ -60,12 +60,16 @@ module ActionView private - def path_to_asset(source, include_host = true) - asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension, include_host) + def path_to_asset(source) + asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension) + end + + def path_to_asset_source(source) + asset_paths.compute_source_path(source, asset_name.to_s.pluralize, extension) end def compute_paths(*args) - expand_sources(*args).collect { |source| asset_paths.compute_public_path(source, asset_name.pluralize, extension, false) } + expand_sources(*args).collect { |source| path_to_asset_source(source) } end def expand_sources(sources, recursive) @@ -92,7 +96,7 @@ module ActionView def ensure_sources!(sources) sources.each do |source| - asset_file_path!(path_to_asset(source, false)) + asset_file_path!(path_to_asset_source(source)) end end @@ -123,19 +127,14 @@ module ActionView # Set mtime to the latest of the combined files to allow for # consistent ETag without a shared filesystem. - mt = asset_paths.map { |p| File.mtime(asset_file_path(p)) }.max + mt = asset_paths.map { |p| File.mtime(asset_file_path!(p)) }.max File.utime(mt, mt, joined_asset_path) end - def asset_file_path(path) - File.join(config.assets_dir, path.split('?').first) - end - - def asset_file_path!(path, error_if_file_is_uri = false) - if asset_paths.is_uri?(path) + def asset_file_path!(absolute_path, error_if_file_is_uri = false) + if asset_paths.is_uri?(absolute_path) raise(Errno::ENOENT, "Asset file #{path} is uri and cannot be merged into single file") if error_if_file_is_uri else - absolute_path = asset_file_path(path) raise(Errno::ENOENT, "Asset file not found at '#{absolute_path}'" ) unless File.exist?(absolute_path) return absolute_path end diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index 9f1f0f3b68..ef7cf9e051 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -58,23 +58,28 @@ module Sprockets end.join("\n").html_safe end + def asset_path(source, default_ext = nil, body = false) + source = source.logical_path if source.respond_to?(:logical_path) + path = asset_paths.compute_public_path(source, 'assets', default_ext) + body ? "#{path}?body=1" : path + end + private def debug_assets? params[:debug_assets] == '1' || params[:debug_assets] == 'true' end - def asset_path(source, default_ext = nil, body = false) - source = source.logical_path if source.respond_to?(:logical_path) - path = asset_paths.compute_public_path(source, Rails.application.config.assets.prefix, default_ext, true) - body ? "#{path}?body=1" : path - end - class AssetPaths < ::ActionView::AssetPaths #:nodoc: def compute_public_path(source, dir, ext=nil, include_host=true) super(source, Rails.application.config.assets.prefix, ext, include_host) end + # Return the filesystem path for the source + def compute_source_path(source, ext) + asset_for(source, ext) + end + def asset_for(source, ext) source = source.to_s return nil if is_uri?(source) @@ -104,7 +109,7 @@ module Sprockets # When included in Sprockets::Context, we need to ask the top-level config as the controller is not available def performing_caching? - @config ? @config.perform_caching : Rails.application.config.action_controller.perform_caching + @config ? @config.perform_caching : Rails.application.config.action_controller.perform_caching end end end diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 2abc806e97..a201a6d1e1 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -1115,14 +1115,14 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase assert_match(%r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_path('xml.png')) end - def test_asset_host_without_protocol_should_use_request_protocol + def test_asset_host_without_protocol_should_be_protocol_relative @controller.config.asset_host = 'a.example.com' - assert_equal 'gopher://a.example.com/collaboration/hieraki/images/xml.png', image_path('xml.png') + assert_equal '//a.example.com/collaboration/hieraki/images/xml.png', image_path('xml.png') end - def test_asset_host_without_protocol_should_use_request_protocol_even_if_path_present + def test_asset_host_without_protocol_should_be_protocol_relative_even_if_path_present @controller.config.asset_host = 'a.example.com/files/go/here' - assert_equal 'gopher://a.example.com/files/go/here/collaboration/hieraki/images/xml.png', image_path('xml.png') + assert_equal '//a.example.com/files/go/here/collaboration/hieraki/images/xml.png', image_path('xml.png') end def test_assert_css_and_js_of_the_same_name_return_correct_extension diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index b1317d0a35..7197a23480 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -31,18 +31,21 @@ class SprocketsHelperTest < ActionView::TestCase Rails.stubs(:application).returns(application) application.stubs(:config).returns(config) application.stubs(:assets).returns(@assets) - - config.perform_caching = true + @config = config + @config.action_controller ||= ActiveSupport::InheritableOptions.new + @config.perform_caching = true end def url_for(*args) "http://www.example.com" end - test "asset path" do + test "asset_path" do assert_equal "/assets/logo-9c0a079bdd7701d7e729bd956823d153.png", asset_path("logo.png") + end + test "asset_path with root relative assets" do assert_equal "/images/logo", asset_path("/images/logo") assert_equal "/images/logo.gif", @@ -50,13 +53,56 @@ class SprocketsHelperTest < ActionView::TestCase assert_equal "/dir/audio", asset_path("/dir/audio") - + end + + test "asset_path with absolute urls" do assert_equal "http://www.example.com/video/play", asset_path("http://www.example.com/video/play") assert_equal "http://www.example.com/video/play.mp4", asset_path("http://www.example.com/video/play.mp4") end + test "with a simple asset host the url should be protocol relative" do + @controller.config.asset_host = "assets-%d.example.com" + assert_match %r{//assets-\d.example.com/assets/logo-[0-9a-f]+.png}, + asset_path("logo.png") + end + + test "With a proc asset host that returns no protocol the url should be protocol relative" do + @controller.config.asset_host = Proc.new do |asset| + "assets-999.example.com" + end + assert_match %r{//assets-999.example.com/assets/logo-[0-9a-f]+.png}, + asset_path("logo.png") + end + + test "with a proc asset host that returns a protocol the url use it" do + @controller.config.asset_host = Proc.new do |asset| + "http://assets-999.example.com" + end + assert_match %r{http://assets-999.example.com/assets/logo-[0-9a-f]+.png}, + asset_path("logo.png") + end + + test "stylesheets served with a controller in scope can access the request" do + config.asset_host = Proc.new do |asset, request| + assert_not_nil request + "http://assets-666.example.com" + end + assert_match %r{http://assets-666.example.com/assets/logo-[0-9a-f]+.png}, + asset_path("logo.png") + end + + test "stylesheets served without a controller in scope cannot access the request" do + remove_instance_variable("@controller") + @config.action_controller.asset_host = Proc.new do |asset, request| + fail "This should not have been called." + end + assert_raises ActionController::RoutingError do + asset_path("logo.png") + end + end + test "asset path with relative url root" do @controller.config.relative_url_root = "/collaboration/hieraki" assert_equal "/collaboration/hieraki/images/logo.gif", -- cgit v1.2.3 From 6c64e1e3a33c2e703a9939f075fb57167b75b36a Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Mon, 27 Jun 2011 13:54:54 -0700 Subject: Stylesheet link tags should use the request protocol to avoid duplicate download of stylesheets in IE7 and IE8. Conflicts: actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb actionpack/lib/sprockets/helpers/rails_helper.rb --- actionpack/lib/action_view/asset_paths.rb | 37 +++++++++++++++++++--- .../helpers/asset_tag_helpers/asset_include_tag.rb | 4 +-- .../asset_tag_helpers/stylesheet_tag_helpers.rb | 10 ++---- actionpack/lib/sprockets/helpers/rails_helper.rb | 10 +++--- actionpack/test/template/asset_tag_helper_test.rb | 16 +++++----- 5 files changed, 50 insertions(+), 27 deletions(-) diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb index 4974bd5426..a74d45db6f 100644 --- a/actionpack/lib/action_view/asset_paths.rb +++ b/actionpack/lib/action_view/asset_paths.rb @@ -13,14 +13,20 @@ module ActionView # Prefix with /dir/ if lacking a leading +/+. Account for relative URL # roots. Rewrite the asset path for cache-busting asset ids. Include # asset host, if configured, with the correct request protocol. - def compute_public_path(source, dir, ext = nil, include_host = true) + # + # When include_host is true and the asset host does not specify the protocol + # the protocol parameter specifies how the protocol will be added. + # When :relative (default), the protocol will be determined by the client using current protocol + # When :request, the protocol will be the request protocol + # Otherwise, the protocol is used (E.g. :http, :https, etc) + def compute_public_path(source, dir, ext = nil, include_host = true, protocol = :relative) source = source.to_s return source if is_uri?(source) source = rewrite_extension(source, dir, ext) if ext source = rewrite_asset_path(source, dir) source = rewrite_relative_url_root(source, relative_url_root) if has_request? - source = rewrite_host_and_protocol(source) if include_host + source = rewrite_host_and_protocol(source, protocol) if include_host source end @@ -52,12 +58,33 @@ module ActionView controller.respond_to?(:request) end - def rewrite_host_and_protocol(source) + def rewrite_host_and_protocol(source, protocol = :relative) host = compute_asset_host(source) - host = "//#{host}" if host && !is_uri?(host) + if host && !is_uri?(host) + host = "#{compute_protocol(protocol)}#{host}" + end host.nil? ? source : "#{host}#{source}" end + def compute_protocol(protocol) + protocol ||= :relative + case protocol + when :relative + "//" + when :request + unless @controller + invalid_asset_host!("The protocol requested was :request. Consider using :relative instead.") + end + @controller.request.protocol + else + "#{protocol}://" + end + end + + def invalid_asset_host!(help_message) + raise ActionController::RoutingError, "This asset host cannot be computed without a request in scope. #{help_message}" + end + # Pick an asset host for this source. Returns +nil+ if no host is set, # the host if no wildcard is set, the host interpolated with the # numbers 0-3 if it contains %d (the number is the source hash mod 4), @@ -69,7 +96,7 @@ module ActionView args = [source] arity = arity_of(host) if arity > 1 && !has_request? - raise ActionController::RoutingError, "This asset host cannot be computed without a request in scope. Remove the second argument to your asset_host Proc if you do not need the request." + invalid_asset_host!("Remove the second argument to your asset_host Proc if you do not need the request.") end args << current_request if (arity > 1 || arity < 0) && has_request? host.call(*args) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb index 16d8f3f893..621f7aaa0a 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb @@ -60,8 +60,8 @@ module ActionView private - def path_to_asset(source) - asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension) + def path_to_asset(source, protocol = :relative) + asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension, true, protocol) end def path_to_asset_source(source) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb index e4f11c9bc7..e829588e94 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb @@ -16,7 +16,7 @@ module ActionView end def asset_tag(source, options) - tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => ERB::Util.html_escape(path_to_asset(source)) }.merge(options), false, false) + tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => ERB::Util.html_escape(path_to_asset(source, :request)) }.merge(options), false, false) end def custom_dir @@ -52,7 +52,7 @@ module ActionView # If the +source+ filename has no extension, .css will be appended (except for explicit URIs). # Full paths from the document root will be passed through. # Used internally by +stylesheet_link_tag+ to build the stylesheet path. - # + # # ==== Examples # stylesheet_path "style" # => /stylesheets/style.css # stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css @@ -60,11 +60,7 @@ module ActionView # stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style # stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css def stylesheet_path(source) - if config.use_sprockets - asset_path(source, 'css') - else - asset_paths.compute_public_path(source, 'stylesheets', 'css') - end + asset_paths.compute_public_path(source, 'stylesheets', 'css', true, :request) end alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index ef7cf9e051..3a77db5fd8 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -50,7 +50,7 @@ module Sprockets 'rel' => "stylesheet", 'type' => "text/css", 'media' => "screen", - 'href' => asset_path(source, 'css', body) + 'href' => asset_path(source, 'css', body, :request) }.merge(options.stringify_keys) tag 'link', tag_options @@ -58,9 +58,9 @@ module Sprockets end.join("\n").html_safe end - def asset_path(source, default_ext = nil, body = false) + def asset_path(source, default_ext = nil, body = false, protocol = :relative) source = source.logical_path if source.respond_to?(:logical_path) - path = asset_paths.compute_public_path(source, 'assets', default_ext) + path = asset_paths.compute_public_path(source, 'assets', default_ext, protocol) body ? "#{path}?body=1" : path end @@ -71,8 +71,8 @@ module Sprockets end class AssetPaths < ::ActionView::AssetPaths #:nodoc: - def compute_public_path(source, dir, ext=nil, include_host=true) - super(source, Rails.application.config.assets.prefix, ext, include_host) + def compute_public_path(source, dir, ext=nil, include_host=true, protocol = :relative) + super(source, Rails.application.config.assets.prefix, ext, include_host, protocol) end # Return the filesystem path for the source diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index a201a6d1e1..cb7ab2572e 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -854,7 +854,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_stylesheet_link_tag_when_caching_on ENV["RAILS_ASSET_ID"] = "" - @controller.config.asset_host = 'http://a0.example.com' + @controller.config.asset_host = 'a0.example.com' config.perform_caching = true assert_dom_equal( @@ -964,7 +964,7 @@ class AssetTagHelperTest < ActionView::TestCase def test_caching_stylesheet_link_tag_when_caching_on_with_proc_asset_host ENV["RAILS_ASSET_ID"] = "" - @controller.config.asset_host = Proc.new { |source| "http://a#{source.length}.example.com" } + @controller.config.asset_host = Proc.new { |source| "a#{source.length}.example.com" } config.perform_caching = true assert_equal '/stylesheets/styles.css'.length, 23 @@ -1091,13 +1091,13 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase end def test_should_compute_proper_path_with_asset_host - @controller.config.asset_host = "http://assets.example.com" + @controller.config.asset_host = "assets.example.com" assert_dom_equal(%(), auto_discovery_link_tag) - assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr")) - assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style")) - assert_dom_equal(%(http://assets.example.com/collaboration/hieraki/images/xml.png), image_path("xml.png")) - assert_dom_equal(%(Mouse), image_tag("mouse.png", :mouseover => "/images/mouse_over.png")) - assert_dom_equal(%(Mouse2), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png"))) + assert_dom_equal(%(//assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr")) + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style")) + assert_dom_equal(%(//assets.example.com/collaboration/hieraki/images/xml.png), image_path("xml.png")) + assert_dom_equal(%(Mouse), image_tag("mouse.png", :mouseover => "/images/mouse_over.png")) + assert_dom_equal(%(Mouse2), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png"))) end def test_should_ignore_asset_host_on_complete_url -- cgit v1.2.3 From 2cc1bc37732a5f89c8364e6724e8c39e14216a0a Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sat, 18 Jun 2011 12:10:09 -0700 Subject: Move the config bootstrapping to initialization to minimize access to the Rails.application global. --- actionpack/lib/action_view/asset_paths.rb | 17 +++++++---------- actionpack/lib/sprockets/helpers/rails_helper.rb | 8 +++++++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb index a74d45db6f..a768a0b882 100644 --- a/actionpack/lib/action_view/asset_paths.rb +++ b/actionpack/lib/action_view/asset_paths.rb @@ -107,20 +107,17 @@ module ActionView end def relative_url_root - if controller.respond_to?(:config) && controller.config - controller.config.relative_url_root - elsif config.respond_to?(:action_controller) && config.action_controller - config.action_controller.relative_url_root - elsif Rails.respond_to?(:application) && Rails.application.config - Rails.application.config.action_controller.relative_url_root - end + config = controller.config if controller.respond_to?(:config) + config ||= config.action_controller if config.action_controller.present? + config ||= config + config.relative_url_root end def asset_host_config - if config.respond_to?(:asset_host) + if config.action_controller.present? + config.action_controller.asset_host + else config.asset_host - elsif Rails.respond_to?(:application) - Rails.application.config.action_controller.asset_host end end diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index 3a77db5fd8..cf185749ea 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -10,6 +10,12 @@ module Sprockets @asset_paths ||= begin config = self.config if respond_to?(:config) controller = self.controller if respond_to?(:controller) + config ||= Rails.application.config + if config.action_controller.present? + config.action_controller.default_asset_host_protocol ||= :relative + else + config.default_asset_host_protocol ||= :relative + end RailsHelper::AssetPaths.new(config, controller) end end @@ -109,7 +115,7 @@ module Sprockets # When included in Sprockets::Context, we need to ask the top-level config as the controller is not available def performing_caching? - @config ? @config.perform_caching : Rails.application.config.action_controller.perform_caching + config.action_controller.present? ? config.action_controller.perform_caching : config.perform_caching end end end -- cgit v1.2.3 From 024bed387b067519de64af5b89ce2b534c99155f Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Mon, 27 Jun 2011 13:58:51 -0700 Subject: Added a configuration setting: config.action_controller.default_asset_host_protocol It's best to leave this unset. When unset the :request protocol is used whenever it can be and :relative is used in the other situations. When set to :request then assets hosts will be disabled when there is no request in scope and will use the request protocol whenever a request is in scope. If set to :relative, then a relative protocol is always used except for stylesheet link tags which must use the :request protocol to avoid double downloads in IE6&7. Conflicts: actionpack/lib/sprockets/helpers/rails_helper.rb actionpack/test/template/sprockets_helper_test.rb --- actionpack/lib/action_view/asset_paths.rb | 18 ++++++++++++++---- .../helpers/asset_tag_helpers/asset_include_tag.rb | 4 ++-- .../asset_tag_helpers/stylesheet_tag_helpers.rb | 3 ++- actionpack/lib/sprockets/helpers/rails_helper.rb | 6 +++--- actionpack/test/template/asset_tag_helper_test.rb | 22 ++++++++++++++++------ actionpack/test/template/sprockets_helper_test.rb | 19 ++++++++++++++++++- 6 files changed, 55 insertions(+), 17 deletions(-) diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb index a768a0b882..4dd02755d3 100644 --- a/actionpack/lib/action_view/asset_paths.rb +++ b/actionpack/lib/action_view/asset_paths.rb @@ -19,7 +19,7 @@ module ActionView # When :relative (default), the protocol will be determined by the client using current protocol # When :request, the protocol will be the request protocol # Otherwise, the protocol is used (E.g. :http, :https, etc) - def compute_public_path(source, dir, ext = nil, include_host = true, protocol = :relative) + def compute_public_path(source, dir, ext = nil, include_host = true, protocol = nil) source = source.to_s return source if is_uri?(source) @@ -58,16 +58,20 @@ module ActionView controller.respond_to?(:request) end - def rewrite_host_and_protocol(source, protocol = :relative) + def rewrite_host_and_protocol(source, protocol = nil) host = compute_asset_host(source) if host && !is_uri?(host) - host = "#{compute_protocol(protocol)}#{host}" + if (protocol || default_protocol) == :request && !has_request? + host = nil + else + host = "#{compute_protocol(protocol)}#{host}" + end end host.nil? ? source : "#{host}#{source}" end def compute_protocol(protocol) - protocol ||= :relative + protocol ||= default_protocol case protocol when :relative "//" @@ -81,6 +85,12 @@ module ActionView end end + def default_protocol + protocol = @config.action_controller.default_asset_host_protocol if @config.action_controller.present? + protocol ||= @config.default_asset_host_protocol + protocol || (has_request? ? :request : :relative) + end + def invalid_asset_host!(help_message) raise ActionController::RoutingError, "This asset host cannot be computed without a request in scope. #{help_message}" end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb index 621f7aaa0a..3c05173a1b 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb @@ -60,8 +60,8 @@ module ActionView private - def path_to_asset(source, protocol = :relative) - asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension, true, protocol) + def path_to_asset(source, include_host = true, protocol = nil) + asset_paths.compute_public_path(source, asset_name.to_s.pluralize, extension, include_host, protocol) end def path_to_asset_source(source) diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb index e829588e94..8c25d38bbd 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb @@ -16,7 +16,8 @@ module ActionView end def asset_tag(source, options) - tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => ERB::Util.html_escape(path_to_asset(source, :request)) }.merge(options), false, false) + # We force the :request protocol here to avoid a double-download bug in IE7 and IE8 + tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => ERB::Util.html_escape(path_to_asset(source, true, :request)) }.merge(options), false, false) end def custom_dir diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index cf185749ea..63820cc76c 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -64,9 +64,9 @@ module Sprockets end.join("\n").html_safe end - def asset_path(source, default_ext = nil, body = false, protocol = :relative) + def asset_path(source, default_ext = nil, body = false, protocol = nil) source = source.logical_path if source.respond_to?(:logical_path) - path = asset_paths.compute_public_path(source, 'assets', default_ext, protocol) + path = asset_paths.compute_public_path(source, 'assets', default_ext, true, protocol) body ? "#{path}?body=1" : path end @@ -77,7 +77,7 @@ module Sprockets end class AssetPaths < ::ActionView::AssetPaths #:nodoc: - def compute_public_path(source, dir, ext=nil, include_host=true, protocol = :relative) + def compute_public_path(source, dir, ext=nil, include_host=true, protocol = nil) super(source, Rails.application.config.assets.prefix, ext, include_host, protocol) end diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index cb7ab2572e..1c4f30a2bc 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -1093,11 +1093,21 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase def test_should_compute_proper_path_with_asset_host @controller.config.asset_host = "assets.example.com" assert_dom_equal(%(), auto_discovery_link_tag) - assert_dom_equal(%(//assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr")) + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr")) assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style")) - assert_dom_equal(%(//assets.example.com/collaboration/hieraki/images/xml.png), image_path("xml.png")) - assert_dom_equal(%(Mouse), image_tag("mouse.png", :mouseover => "/images/mouse_over.png")) - assert_dom_equal(%(Mouse2), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png"))) + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/images/xml.png), image_path("xml.png")) + assert_dom_equal(%(Mouse), image_tag("mouse.png", :mouseover => "/images/mouse_over.png")) + assert_dom_equal(%(Mouse2), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png"))) + end + + def test_should_compute_proper_path_with_asset_host_and_default_protocol + @controller.config.asset_host = "assets.example.com" + @controller.config.default_asset_host_protocol = :request + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr")) + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style")) + assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/images/xml.png), image_path("xml.png")) + assert_dom_equal(%(Mouse), image_tag("mouse.png", :mouseover => "/images/mouse_over.png")) + assert_dom_equal(%(Mouse2), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png"))) end def test_should_ignore_asset_host_on_complete_url @@ -1117,12 +1127,12 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase def test_asset_host_without_protocol_should_be_protocol_relative @controller.config.asset_host = 'a.example.com' - assert_equal '//a.example.com/collaboration/hieraki/images/xml.png', image_path('xml.png') + assert_equal 'gopher://a.example.com/collaboration/hieraki/images/xml.png', image_path('xml.png') end def test_asset_host_without_protocol_should_be_protocol_relative_even_if_path_present @controller.config.asset_host = 'a.example.com/files/go/here' - assert_equal '//a.example.com/files/go/here/collaboration/hieraki/images/xml.png', image_path('xml.png') + assert_equal 'gopher://a.example.com/files/go/here/collaboration/hieraki/images/xml.png', image_path('xml.png') end def test_assert_css_and_js_of_the_same_name_return_correct_extension diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb index 7197a23480..6dc9a2a743 100644 --- a/actionpack/test/template/sprockets_helper_test.rb +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -62,11 +62,18 @@ class SprocketsHelperTest < ActionView::TestCase asset_path("http://www.example.com/video/play.mp4") end - test "with a simple asset host the url should be protocol relative" do + test "with a simple asset host the url should default to protocol relative" do @controller.config.asset_host = "assets-%d.example.com" assert_match %r{//assets-\d.example.com/assets/logo-[0-9a-f]+.png}, asset_path("logo.png") end + + test "with a simple asset host the url can be changed to use the request protocol" do + @controller.config.asset_host = "assets-%d.example.com" + @controller.config.default_asset_host_protocol = :request + assert_match %r{http://assets-\d.example.com/assets/logo-[0-9a-f]+.png}, + asset_path("logo.png") + end test "With a proc asset host that returns no protocol the url should be protocol relative" do @controller.config.asset_host = Proc.new do |asset| @@ -103,6 +110,16 @@ class SprocketsHelperTest < ActionView::TestCase end end + test "stylesheets served without a controller in do not use asset hosts when the default protocol is :request" do + remove_instance_variable("@controller") + @config.action_controller.asset_host = "assets-%d.example.com" + @config.action_controller.default_asset_host_protocol = :request + @config.action_controller.perform_caching = true + + assert_equal "/assets/logo-9c0a079bdd7701d7e729bd956823d153.png", + asset_path("logo.png") + end + test "asset path with relative url root" do @controller.config.relative_url_root = "/collaboration/hieraki" assert_equal "/collaboration/hieraki/images/logo.gif", -- cgit v1.2.3