aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/abstract_controller/rendering.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/abstract_controller/rendering.rb')
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb212
1 files changed, 58 insertions, 154 deletions
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index 619a49571b..42f4939108 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -1,7 +1,4 @@
require "abstract_controller/base"
-require 'active_support/core_ext/class/attribute'
-require 'active_support/core_ext/module/delegation'
-require 'active_support/core_ext/array/wrap'
module AbstractController
class DoubleRenderError < Error
@@ -12,32 +9,47 @@ module AbstractController
end
end
+ # This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
+ # it will trigger the lookup_context and consequently expire the cache.
+ # TODO Add some deprecation warnings to remove I18n.locale from controllers
+ class I18nProxy < ::I18n::Config #:nodoc:
+ attr_reader :i18n_config, :lookup_context
+
+ def initialize(i18n_config, lookup_context)
+ @i18n_config, @lookup_context = i18n_config, lookup_context
+ end
+
+ def locale
+ @i18n_config.locale
+ end
+
+ def locale=(value)
+ @i18n_config.locale = value
+ @lookup_context.update_details(:locale => @i18n_config.locale)
+ end
+ end
+
module Rendering
extend ActiveSupport::Concern
+ include AbstractController::ViewPaths
- included do
- class_attribute :_view_paths
- delegate :_view_paths, :to => :'self.class'
- self._view_paths = ActionView::PathSet.new
+ # Overwrite process to setup I18n proxy.
+ def process(*) #:nodoc:
+ old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
+ super
+ ensure
+ I18n.config = old_config
end
# An instance of a view class. The default view class is ActionView::Base
#
# The view class must have the following methods:
- # View.for_controller[controller] Create a new ActionView instance for a
- # controller
- # View#render_partial[options]
- # - responsible for setting options[:_template]
- # - Returns String with the rendered partial
- # options<Hash>:: see _render_partial in ActionView::Base
- # View#render_template[template, layout, options, partial]
- # - Returns String with the rendered template
- # template<ActionView::Template>:: The template to render
- # layout<ActionView::Template>:: The layout to render around the template
- # options<Hash>:: See _render_template_with_layout in ActionView::Base
- # partial<Boolean>:: Whether or not the template to render is a partial
+ # View.for_controller[controller]
+ # Create a new ActionView instance for a controller
+ # View#render_template[options]
+ # Returns String with the rendered template
#
- # Override this method in a to change the default behavior.
+ # Override this method in a module to change the default behavior.
def view_context
@_view_context ||= ActionView::Base.for_controller(self)
end
@@ -45,57 +57,29 @@ module AbstractController
# Mostly abstracts the fact that calling render twice is a DoubleRenderError.
# Delegates render_to_body and sticks the result in self.response_body.
def render(*args, &block)
- options = _normalize_options(*args, &block)
+ options = _normalize_args(*args, &block)
+ _normalize_options(options)
self.response_body = render_to_body(options)
end
# Raw rendering of a template to a Rack-compatible body.
- #
- # ==== Options
- # _partial_object<Object>:: The object that is being rendered. If this
- # exists, we are in the special case of rendering an object as a partial.
- #
# :api: plugin
def render_to_body(options = {})
- # TODO: Refactor so we can just use the normal template logic for this
- if options.key?(:partial)
- _render_partial(options)
- else
- _determine_template(options)
- _render_template(options)
- end
+ _process_options(options)
+ _render_template(options)
end
# Raw rendering of a template to a string. Just convert the results of
# render_to_body into a String.
- #
# :api: plugin
- def render_to_string(*args)
- options = _normalize_options(*args)
+ def render_to_string(options={})
+ _normalize_options(options)
AbstractController::Rendering.body_to_s(render_to_body(options))
end
- # Renders the template from an object.
- #
- # ==== Options
- # _template<ActionView::Template>:: The template to render
- # _layout<ActionView::Template>:: The layout to wrap the template in (optional)
+ # Find and renders a template based on the options given.
def _render_template(options)
- view_context.render_template(options)
- end
-
- # Renders the given partial.
- #
- # ==== Options
- # partial<String|Object>:: The partial name or the object to be rendered
- def _render_partial(options)
- view_context.render_partial(options)
- end
-
- # The list of view paths for this controller. See ActionView::ViewPathSet for
- # more details about writing custom view paths.
- def view_paths
- _view_paths
+ view_context.render_template(options) { |template| _with_template_hook(template) }
end
# The prefix used in render "foo" shortcuts.
@@ -117,122 +101,42 @@ module AbstractController
private
- # Normalize options, by converting render "foo" to render :template => "prefix/foo"
- # and render "/foo" to render :file => "/foo".
- def _normalize_options(action=nil, options={})
+ # Normalize options by converting render "foo" to render :action => "foo" and
+ # render "foo/bar" to render :file => "foo/bar".
+ def _normalize_args(action=nil, options={})
case action
+ when NilClass
when Hash
options, action = action, nil
when String, Symbol
action = action.to_s
- case action.index("/")
- when NilClass
- options[:_prefix] = _prefix
- options[:_template_name] = action
- when 0
- options[:file] = action
- else
- options[:template] = action
- end
+ key = action.include?(?/) ? :file : :action
+ options[key] = action
+ else
+ options.merge!(:partial => action)
end
options
end
- # Take in a set of options and determine the template to render
- #
- # ==== Options
- # _template<ActionView::Template>:: If this is provided, the search is over
- # _template_name<#to_s>:: The name of the template to look up. Otherwise,
- # use the current action name.
- # _prefix<String>:: The prefix to look inside of. In a file system, this corresponds
- # to a directory.
- # _partial<TrueClass, FalseClass>:: Whether or not the file to look up is a partial
- def _determine_template(options)
- if options.key?(:text)
- options[:_template] = ActionView::Template::Text.new(options[:text], format_for_text)
- elsif options.key?(:inline)
- handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb")
- template = ActionView::Template.new(options[:inline], "inline template", handler, {})
- options[:_template] = template
- elsif options.key?(:template)
- options[:_template_name] = options[:template]
- elsif options.key?(:file)
- options[:_template_name] = options[:file]
+ def _normalize_options(options)
+ if options[:partial] == true
+ options[:partial] = action_name
end
- name = (options[:_template_name] || options[:action] || action_name).to_s
- options[:_prefix] ||= _prefix if (options.keys & [:partial, :file, :template]).empty?
-
- details = _normalize_details(options)
- options[:_template] ||= with_template_cache(name) do
- find_template(name, details, options)
+ if (options.keys & [:partial, :file, :template]).empty?
+ options[:prefix] ||= _prefix
end
- end
-
- def _normalize_details(options)
- details = { :formats => formats }
- details[:formats] = Array(options[:format]) if options[:format]
- details[:locale] = Array(options[:locale]) if options[:locale]
- details
- end
- def find_template(name, details, options)
- view_paths.find(name, details, options[:_prefix], options[:_partial])
- end
-
- def template_exists?(name, details, options)
- view_paths.exists?(name, details, options[:_prefix], options[:_partial])
- end
-
- def with_template_cache(name)
- yield
+ options[:template] ||= (options[:action] || action_name).to_s
+ options
end
- def format_for_text
- Mime[:text]
+ def _process_options(options)
end
- module ClassMethods
- def clear_template_caches!
- end
-
- # Append a path to the list of view paths for this controller.
- #
- # ==== Parameters
- # path<String, ViewPath>:: If a String is provided, it gets converted into
- # the default view path. You may also provide a custom view path
- # (see ActionView::ViewPathSet for more information)
- def append_view_path(path)
- self.view_paths = view_paths.dup + Array.wrap(path)
- end
-
- # Prepend a path to the list of view paths for this controller.
- #
- # ==== Parameters
- # path<String, ViewPath>:: If a String is provided, it gets converted into
- # the default view path. You may also provide a custom view path
- # (see ActionView::ViewPathSet for more information)
- def prepend_view_path(path)
- clear_template_caches!
- self.view_paths = Array.wrap(path) + view_paths.dup
- end
-
- # A list of all of the default view paths for this controller.
- def view_paths
- _view_paths
- end
-
- # Set the view paths.
- #
- # ==== Parameters
- # paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that;
- # otherwise, process the parameter into a ViewPathSet.
- def view_paths=(paths)
- clear_template_caches!
- self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths)
- _view_paths.freeze
- end
+ def _with_template_hook(template)
+ self.formats = template.formats
end
end
end