diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2014-02-13 17:24:22 +0100 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2014-02-13 17:24:22 +0100 |
commit | f2dfa83fac5e892335d2bceaa6dfe344515fee26 (patch) | |
tree | 8e0f89eefe15f5bff61e111cbbc718114d9a0820 | |
parent | ea3af7ee14217470b019225a03cccced1120f211 (diff) | |
parent | f9b6b865e60ea770cc34e9946f6df1604f20dd27 (diff) | |
download | rails-f2dfa83fac5e892335d2bceaa6dfe344515fee26.tar.gz rails-f2dfa83fac5e892335d2bceaa6dfe344515fee26.tar.bz2 rails-f2dfa83fac5e892335d2bceaa6dfe344515fee26.zip |
Merge pull request #14043 from strzalek/variants-negotiation
Variant negotiation
-rw-r--r-- | actionpack/lib/action_controller/metal/mime_responds.rb | 28 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/mime_negotiation.rb | 6 | ||||
-rw-r--r-- | actionpack/test/controller/mime/respond_to_test.rb | 21 | ||||
-rw-r--r-- | actionpack/test/dispatch/request_test.rb | 6 | ||||
-rw-r--r-- | actionview/lib/action_view/rendering.rb | 2 |
5 files changed, 51 insertions, 12 deletions
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index d5e08b7034..c8076af0c8 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -236,6 +236,18 @@ module ActionController #:nodoc: # end # end # + # You can also set an array of variants: + # + # request.variant = [:tablet, :phone] + # + # which will work similarly to formats and MIME types negotiation. If there will be no + # :tablet variant declared, :phone variant will be picked: + # + # respond_to do |format| + # format.html.none + # format.html.phone # this gets rendered + # end + # # Be sure to check the documentation of +respond_with+ and # <tt>ActionController::MimeResponds.respond_to</tt> for more examples. def respond_to(*mimes, &block) @@ -488,7 +500,7 @@ module ActionController #:nodoc: response else # `format.html{ |variant| variant.phone }` - variant block syntax variant_collector = VariantCollector.new(@variant) - response.call(variant_collector) #call format block with variants collector + response.call(variant_collector) # call format block with variants collector variant_collector.variant end end @@ -519,15 +531,15 @@ module ActionController #:nodoc: end def variant - key = if @variant.nil? - :none - elsif @variants.has_key?(@variant) - @variant + if @variant.nil? + @variants[:none] + elsif (@variants.keys & @variant).any? + @variant.each do |v| + return @variants[v] if @variants.key?(v) + end else - :any + @variants[:any] end - - @variants[key] end end end diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index c33ba201e1..b75d7ffe9d 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -68,10 +68,12 @@ module ActionDispatch # Sets the \variant for template. def variant=(variant) - if variant.is_a? Symbol + if variant.is_a?(Symbol) + @variant = [variant] + elsif variant.is_a?(Array) @variant = variant else - raise ArgumentError, "request.variant must be set to a Symbol, not a #{variant.class}. " \ + raise ArgumentError, "request.variant must be set to a Symbol or Array, not a #{variant.class}. " \ "For security reasons, never directly set the variant to a user-provided value, " \ "like params[:variant].to_sym. Check user-provided value against a whitelist first, " \ "then set the variant: request.variant = :tablet if params[:variant] == 'tablet'" diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb index 84e4936f31..2f05017ec9 100644 --- a/actionpack/test/controller/mime/respond_to_test.rb +++ b/actionpack/test/controller/mime/respond_to_test.rb @@ -740,4 +740,25 @@ class RespondToControllerTest < ActionController::TestCase assert_equal "text/javascript", @response.content_type assert_equal "tablet", @response.body end + + def test_variant_negotiation_inline_syntax + @request.variant = [:tablet, :phone] + get :variant_inline_syntax_without_block + assert_equal "text/html", @response.content_type + assert_equal "phone", @response.body + end + + def test_variant_negotiation_block_syntax + @request.variant = [:tablet, :phone] + get :variant_plus_none_for_format + assert_equal "text/html", @response.content_type + assert_equal "phone", @response.body + end + + def test_variant_negotiation_without_block + @request.variant = [:tablet, :phone] + get :variant_inline_syntax_without_block + assert_equal "text/html", @response.content_type + assert_equal "phone", @response.body + end end diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index f79fe47897..df47520850 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -846,8 +846,12 @@ class RequestTest < ActiveSupport::TestCase test "setting variant" do request = stub_request + request.variant = :mobile - assert_equal :mobile, request.variant + assert_equal [:mobile], request.variant + + request.variant = [:phone, :tablet] + assert_equal [:phone, :tablet], request.variant end test "setting variant with non symbol value" do diff --git a/actionview/lib/action_view/rendering.rb b/actionview/lib/action_view/rendering.rb index 99b95fdfb7..7c17220d14 100644 --- a/actionview/lib/action_view/rendering.rb +++ b/actionview/lib/action_view/rendering.rb @@ -94,7 +94,7 @@ module ActionView variant = options[:variant] lookup_context.rendered_format = nil if options[:formats] - lookup_context.variants = [variant] if variant + lookup_context.variants = variant if variant view_renderer.render(view_context, options) end |