aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Heinemeier Hansson <david@loudthinking.com>2014-02-13 17:24:22 +0100
committerDavid Heinemeier Hansson <david@loudthinking.com>2014-02-13 17:24:22 +0100
commitf2dfa83fac5e892335d2bceaa6dfe344515fee26 (patch)
tree8e0f89eefe15f5bff61e111cbbc718114d9a0820
parentea3af7ee14217470b019225a03cccced1120f211 (diff)
parentf9b6b865e60ea770cc34e9946f6df1604f20dd27 (diff)
downloadrails-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.rb28
-rw-r--r--actionpack/lib/action_dispatch/http/mime_negotiation.rb6
-rw-r--r--actionpack/test/controller/mime/respond_to_test.rb21
-rw-r--r--actionpack/test/dispatch/request_test.rb6
-rw-r--r--actionview/lib/action_view/rendering.rb2
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