diff options
author | Łukasz Strzałkowski <lukasz.strzalkowski@gmail.com> | 2013-12-03 11:17:01 +0100 |
---|---|---|
committer | Łukasz Strzałkowski <lukasz.strzalkowski@gmail.com> | 2013-12-04 00:13:16 +0100 |
commit | 2d3a6a0cb8df0360dd588a4d2fb260dd07cc9bcf (patch) | |
tree | 7f0c914f8af3585b4df30bd8f19784aeefae1e99 /actionpack/lib/action_controller | |
parent | 4d648819c5662f375b8ca431a14511ae6a97a29c (diff) | |
download | rails-2d3a6a0cb8df0360dd588a4d2fb260dd07cc9bcf.tar.gz rails-2d3a6a0cb8df0360dd588a4d2fb260dd07cc9bcf.tar.bz2 rails-2d3a6a0cb8df0360dd588a4d2fb260dd07cc9bcf.zip |
Action Pack Variants
By default, variants in the templates will be picked up if a variant is set
and there's a match. The format will be:
app/views/projects/show.html.erb
app/views/projects/show.html+tablet.erb
app/views/projects/show.html+phone.erb
If request.variant = :tablet is set, we'll automatically be rendering the
html+tablet template.
In the controller, we can also tailer to the variants with this syntax:
class ProjectsController < ActionController::Base
def show
respond_to do |format|
format.html do |html|
@stars = @project.stars
html.tablet { @notifications = @project.notifications }
html.phone { @chat_heads = @project.chat_heads }
end
format.js
format.atom
end
end
end
The variant itself is nil by default, but can be set in before filters, like
so:
class ApplicationController < ActionController::Base
before_action do
if request.user_agent =~ /iPad/
request.variant = :tablet
end
end
end
This is modeled loosely on custom mime types, but it's specifically not
intended to be used together. If you're going to make a custom mime type,
you don't need a variant. Variants are for variations on a single mime
types.
Diffstat (limited to 'actionpack/lib/action_controller')
-rw-r--r-- | actionpack/lib/action_controller/metal/mime_responds.rb | 50 |
1 files changed, 46 insertions, 4 deletions
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index 84ade41036..9a88a01233 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -181,13 +181,40 @@ module ActionController #:nodoc: # end # end # + # Formats can have different variants. + # + # The request variant is a specialization of the request format, like <tt>:tablet</tt>, + # <tt>:phone</tt>, or <tt>:desktop<tt>. + # + # We often want to render different html/json/xml templates for phones, + # tablets, and desktop browsers. Variants make it easy. + # + # You can set the variant in a +before_action+: + # + # request.variant = :tablet if request.user_agent =~ /iPad/ + # + # Respond to variants in the action just like you respond to formats: + # + # respond_to do |format| + # format.html do |html| + # html.tablet # renders app/views/projects/show.html+tablet.erb + # html.phone { extra_setup; render ... } + # end + # end + # + # Provide separate templates for each format and variant: + # + # app/views/projects/show.html.erb + # app/views/projects/show.html+tablet.erb + # app/views/projects/show.html+phone.erb + # # Be sure to check the documentation of +respond_with+ and # <tt>ActionController::MimeResponds.respond_to</tt> for more examples. def respond_to(*mimes, &block) raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given? if collector = retrieve_collector_from_mimes(mimes, &block) - response = collector.response + response = collector.response(request.variant) response ? response.call : render({}) end end @@ -327,7 +354,7 @@ module ActionController #:nodoc: if collector = retrieve_collector_from_mimes(&block) options = resources.size == 1 ? {} : resources.extract_options! options = options.clone - options[:default_response] = collector.response + options[:default_response] = collector.response(request.variant) (options.delete(:responder) || self.class.responder).call(self, resources, options) end end @@ -417,13 +444,28 @@ module ActionController #:nodoc: @responses[mime_type] ||= block end - def response - @responses.fetch(format, @responses[Mime::ALL]) + def response(variant) + response = @responses.fetch(format, @responses[Mime::ALL]) + if response.nil? || response.arity == 0 + response + else + lambda { response.call VariantFilter.new(variant) } + end end def negotiate_format(request) @format = request.negotiate_mime(@responses.keys) end + + class VariantFilter + def initialize(variant) + @variant = variant + end + + def method_missing(name) + yield if name == @variant + end + end end end end |