diff options
Diffstat (limited to 'actionpack/lib/abstract_controller')
-rw-r--r-- | actionpack/lib/abstract_controller/asset_paths.rb | 4 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/base.rb | 27 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/callbacks.rb | 6 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/helpers.rb | 24 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/layouts.rb | 8 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/rendering.rb | 100 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/view_paths.rb | 37 |
7 files changed, 124 insertions, 82 deletions
diff --git a/actionpack/lib/abstract_controller/asset_paths.rb b/actionpack/lib/abstract_controller/asset_paths.rb index 9ca2fb742f..ad14cd6d87 100644 --- a/actionpack/lib/abstract_controller/asset_paths.rb +++ b/actionpack/lib/abstract_controller/asset_paths.rb @@ -3,7 +3,7 @@ module AbstractController extend ActiveSupport::Concern included do - config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, :stylesheets_dir + config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, :stylesheets_dir, :use_sprockets end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index c384fd0978..f67d0e558e 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -1,3 +1,4 @@ +require 'erubis' require 'active_support/configurable' require 'active_support/descendants_tracker' require 'active_support/core_ext/module/anonymous' @@ -18,6 +19,7 @@ module AbstractController include ActiveSupport::Configurable extend ActiveSupport::DescendantsTracker + undef_method :not_implemented class << self attr_reader :abstract alias_method :abstract?, :abstract @@ -128,17 +130,29 @@ module AbstractController self.class.action_methods end + # Returns true if a method for the action is available and + # can be dispatched, false otherwise. + # + # Notice that <tt>action_methods.include?("foo")</tt> may return + # false and <tt>available_action?("foo")</tt> returns true because + # available action consider actions that are also available + # through other means, for example, implicit render ones. + def available_action?(action_name) + method_for_action(action_name).present? + end + private - # Returns true if the name can be considered an action. This can - # be overridden in subclasses to modify the semantics of what - # can be considered an action. + # Returns true if the name can be considered an action because + # it has a method defined in the controller. # # ==== Parameters # * <tt>name</tt> - The name of an action to be tested # # ==== Returns # * <tt>TrueClass</tt>, <tt>FalseClass</tt> + # + # :api: private def action_method?(name) self.class.action_methods.include?(name) end @@ -146,6 +160,9 @@ module AbstractController # Call the action. Override this in a subclass to modify the # behavior around processing an action. This, and not #process, # is the intended way to override action dispatching. + # + # Notice that the first argument is the method to be dispatched + # which is *not* necessarily the same as the action name. def process_action(method_name, *args) send_action(method_name, *args) end @@ -160,8 +177,8 @@ module AbstractController # If the action name was not found, but a method called "action_missing" # was found, #method_for_action will return "_handle_action_missing". # This method calls #action_missing with the current action name. - def _handle_action_missing - action_missing(@_action_name) + def _handle_action_missing(*args) + action_missing(@_action_name, *args) end # Takes an action name and returns the name of the method that will diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index 95992c2698..e8426bc52b 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -13,8 +13,8 @@ module AbstractController # Override AbstractController::Base's process_action to run the # process_action callbacks around the normal behavior. - def process_action(method_name, *args) - run_callbacks(:process_action, method_name) do + def process_action(*args) + run_callbacks(:process_action, action_name) do super end end @@ -29,7 +29,7 @@ module AbstractController # # ==== Options # * <tt>only</tt> - The callback should be run only for this action - # * <tt>except<tt> - The callback should be run for all actions except this action + # * <tt>except</tt> - The callback should be run for all actions except this action def _normalize_callback_options(options) if only = options[:only] only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ") diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb index 20f8601a8e..dc9778a416 100644 --- a/actionpack/lib/abstract_controller/helpers.rb +++ b/actionpack/lib/abstract_controller/helpers.rb @@ -4,8 +4,6 @@ module AbstractController module Helpers extend ActiveSupport::Concern - include Rendering - included do class_attribute :_helpers self._helpers = Module.new @@ -112,17 +110,6 @@ module AbstractController default_helper_module! unless anonymous? end - private - # Makes all the (instance) methods in the helper module available to templates - # rendered through this controller. - # - # ==== Parameters - # * <tt>module</tt> - The module to include into the current helper module - # for the class - def add_template_helper(mod) - _helpers.module_eval { include mod } - end - # Returns a list of modules, normalized from the acceptable kinds of # helpers with the following behavior: # @@ -155,6 +142,17 @@ module AbstractController end end + private + # Makes all the (instance) methods in the helper module available to templates + # rendered through this controller. + # + # ==== Parameters + # * <tt>module</tt> - The module to include into the current helper module + # for the class + def add_template_helper(mod) + _helpers.module_eval { include mod } + end + def default_helper_module! module_name = name.sub(/Controller$/, '') module_path = module_name.underscore diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 4ee54474cc..8f73e244d7 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -292,15 +292,15 @@ module AbstractController end end - attr_writer :action_has_layout + attr_internal_writer :action_has_layout def initialize(*) - @action_has_layout = true + @_action_has_layout = true super end def action_has_layout? - @action_has_layout + @_action_has_layout end private @@ -334,7 +334,7 @@ module AbstractController # ==== Parameters # * <tt>details</tt> - A list of details to restrict the search by. This # might include details like the format or locale of the template. - # * <tt>require_logout</tt> - If this is true, raise an ArgumentError + # * <tt>require_layout</tt> - If this is true, raise an ArgumentError # with details about the fact that the exception could not be # found (defaults to false) # diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 691310d5d2..ab2c532859 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -1,5 +1,6 @@ require "abstract_controller/base" require "action_view" +require "active_support/core_ext/object/instance_variables" module AbstractController class DoubleRenderError < Error @@ -31,9 +32,13 @@ module AbstractController module Rendering extend ActiveSupport::Concern - include AbstractController::ViewPaths + included do + config_accessor :protected_instance_variables, :instance_reader => false + self.protected_instance_variables = [] + end + # Overwrite process to setup I18n proxy. def process(*) #:nodoc: old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context) @@ -45,46 +50,27 @@ module AbstractController module ClassMethods def view_context_class @view_context_class ||= begin - controller = self - Class.new(ActionView::Base) do - if controller.respond_to?(:_routes) && controller._routes - include controller._routes.url_helpers - include controller._routes.mounted_helpers - end - - if controller.respond_to?(:_helpers) - include controller._helpers - - # TODO: Fix RJS to not require this - self.helpers = controller._helpers - end - end + routes = _routes if respond_to?(:_routes) + helpers = _helpers if respond_to?(:_helpers) + ActionView::Base.prepare(routes, helpers) end end + end - def parent_prefixes - @parent_prefixes ||= begin - parent_controller = superclass - prefixes = [] - - until parent_controller.abstract? - prefixes << parent_controller.controller_path - parent_controller = parent_controller.superclass - end + attr_internal_writer :view_context_class - prefixes - end - end + # Explicitly define protected_instance_variables so it can be + # inherited and overwritten by other modules if needed. + def protected_instance_variables + config.protected_instance_variables end - attr_writer :view_context_class - def view_context_class - @view_context_class || self.class.view_context_class + @_view_context_class || self.class.view_context_class end def initialize(*) - @view_context_class = nil + @_view_context_class = nil super end @@ -98,22 +84,27 @@ module AbstractController # # Override this method in a module to change the default behavior. def view_context - view_context_class.new(lookup_context, view_assigns, self) + view_context_class.new(view_renderer, view_assigns, self) + end + + # Returns an object that is able to render templates. + def view_renderer + @_view_renderer ||= ActionView::Renderer.new(lookup_context) end # Normalize arguments, options and then delegates render_to_body and # sticks the result in self.response_body. def render(*args, &block) - self.response_body = render_to_string(*args, &block) + options = _normalize_render(*args, &block) + self.response_body = render_to_body(options) end # Raw rendering of a template to a string. Just convert the results of - # render_to_body into a String. + # render_response into a String. # :api: plugin def render_to_string(*args, &block) - options = _normalize_args(*args, &block) - _normalize_options(options) - render_to_body(options).tap { self.response_body = nil } + options = _normalize_render(*args, &block) + render_to_body(options) end # Raw rendering of a template to a Rack-compatible body. @@ -126,32 +117,39 @@ module AbstractController # Find and renders a template based on the options given. # :api: private def _render_template(options) #:nodoc: - view_context.render(options) - end - - # The prefixes used in render "foo" shortcuts. - def _prefixes - @_prefixes ||= begin - parent_prefixes = self.class.parent_prefixes - parent_prefixes.dup.unshift(controller_path) - end + view_renderer.render(view_context, options) end private + DEFAULT_PROTECTED_INSTANCE_VARIABLES = %w( + @_action_name @_response_body @_formats @_prefixes @_config + @_view_context_class @_view_renderer @_lookup_context + ) + # This method should return a hash with assigns. # You can overwrite this configuration per controller. # :api: public def view_assigns hash = {} variables = instance_variable_names - variables -= protected_instance_variables if respond_to?(:protected_instance_variables) + variables -= protected_instance_variables + variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES variables.each { |name| hash[name.to_s[1, name.length]] = instance_variable_get(name) } hash end - # Normalize options by converting render "foo" to render :action => "foo" and + # Normalize args and options. + # :api: private + def _normalize_render(*args, &block) + options = _normalize_args(*args, &block) + _normalize_options(options) + options + end + + # Normalize args by converting render "foo" to render :action => "foo" and # render "foo/bar" to render :file => "foo/bar". + # :api: plugin def _normalize_args(action=nil, options={}) case action when NilClass @@ -168,12 +166,14 @@ module AbstractController options end + # Normalize options. + # :api: plugin def _normalize_options(options) if options[:partial] == true options[:partial] = action_name end - if (options.keys & [:partial, :file, :template, :once]).empty? + if (options.keys & [:partial, :file, :template]).empty? options[:prefixes] ||= _prefixes end @@ -181,6 +181,8 @@ module AbstractController options end + # Process extra options. + # :api: plugin def _process_options(options) end end diff --git a/actionpack/lib/abstract_controller/view_paths.rb b/actionpack/lib/abstract_controller/view_paths.rb index 6544c8949a..6b7aae8c74 100644 --- a/actionpack/lib/abstract_controller/view_paths.rb +++ b/actionpack/lib/abstract_controller/view_paths.rb @@ -11,11 +11,36 @@ module AbstractController delegate :find_template, :template_exists?, :view_paths, :formats, :formats=, :locale, :locale=, :to => :lookup_context + module ClassMethods + def parent_prefixes + @parent_prefixes ||= begin + parent_controller = superclass + prefixes = [] + + until parent_controller.abstract? + prefixes << parent_controller.controller_path + parent_controller = parent_controller.superclass + end + + prefixes + end + end + end + + # The prefixes used in render "foo" shortcuts. + def _prefixes + @_prefixes ||= begin + parent_prefixes = self.class.parent_prefixes + parent_prefixes.dup.unshift(controller_path) + end + end + # LookupContext is the object responsible to hold all information required to lookup # templates, i.e. view paths and details. Check ActionView::LookupContext for more # information. def lookup_context - @lookup_context ||= ActionView::LookupContext.new(self.class._view_paths, details_for_lookup) + @_lookup_context ||= + ActionView::LookupContext.new(self.class._view_paths, details_for_lookup, _prefixes) end def details_for_lookup @@ -36,7 +61,7 @@ module AbstractController # ==== Parameters # * <tt>path</tt> - 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) + # (see ActionView::PathSet for more information) def append_view_path(path) self.view_paths = view_paths.dup + Array(path) end @@ -46,7 +71,7 @@ module AbstractController # ==== Parameters # * <tt>path</tt> - 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) + # (see ActionView::PathSet for more information) def prepend_view_path(path) self.view_paths = Array(path) + view_paths.dup end @@ -59,12 +84,12 @@ module AbstractController # Set the view paths. # # ==== Parameters - # * <tt>paths</tt> - If a ViewPathSet is provided, use that; - # otherwise, process the parameter into a ViewPathSet. + # * <tt>paths</tt> - If a PathSet is provided, use that; + # otherwise, process the parameter into a PathSet. def view_paths=(paths) self._view_paths = ActionView::Base.process_view_paths(paths) self._view_paths.freeze end end end -end
\ No newline at end of file +end |