diff options
| author | Pratik Naik <pratiknaik@gmail.com> | 2009-05-15 16:47:15 +0200 |
|---|---|---|
| committer | Pratik Naik <pratiknaik@gmail.com> | 2009-05-15 16:47:15 +0200 |
| commit | 59653101b8cef7915cb1fb4ad4b84f49ae0881e5 (patch) | |
| tree | 9dacd7eaa05c7957b14389538a30d7ebf7f7e349 /actionpack/lib/action_controller/abstract | |
| parent | 26ad104e72e2b758815a043341dd83a1b02e8c7f (diff) | |
| parent | eb021707f53be46140b55a48e5ef03ed0577a45c (diff) | |
| download | rails-59653101b8cef7915cb1fb4ad4b84f49ae0881e5.tar.gz rails-59653101b8cef7915cb1fb4ad4b84f49ae0881e5.tar.bz2 rails-59653101b8cef7915cb1fb4ad4b84f49ae0881e5.zip | |
Merge commit 'mainstream/master'
Conflicts:
actionpack/lib/action_view/helpers/form_helper.rb
Diffstat (limited to 'actionpack/lib/action_controller/abstract')
6 files changed, 166 insertions, 43 deletions
diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index ade7719cc0..f2db201063 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -1,41 +1,112 @@ +require 'active_support/core_ext/module/attr_internal' + module AbstractController + class Error < StandardError; end + + class DoubleRenderError < Error + DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." + + def initialize(message = nil) + super(message || DEFAULT_MESSAGE) + end + end + class Base attr_internal :response_body attr_internal :response_obj attr_internal :action_name - - def self.process(action) - new.process(action) + + class << self + attr_reader :abstract + + def abstract! + @abstract = true + end + + alias_method :abstract?, :abstract + + def inherited(klass) + ::AbstractController::Base.subclasses << klass.to_s + super + end + + def subclasses + @subclasses ||= [] + end + + def internal_methods + controller = self + controller = controller.superclass until controller.abstract? + controller.public_instance_methods(true) + end + + def process(action) + new.process(action.to_s) + end + + def hidden_actions + [] + end + + def action_methods + @action_methods ||= + # All public instance methods of this class, including ancestors + public_instance_methods(true).map { |m| m.to_s }.to_set - + # Except for public instance methods of Base and its ancestors + internal_methods.map { |m| m.to_s } + + # Be sure to include shadowed public instance methods of this class + public_instance_methods(false).map { |m| m.to_s } - + # And always exclude explicitly hidden actions + hidden_actions + end end - def self.inherited(klass) - end + abstract! def initialize self.response_obj = {} end def process(action_name) + action_name = action_name.to_s + unless respond_to_action?(action_name) raise ActionNotFound, "The action '#{action_name}' could not be found" end @_action_name = action_name process_action - self.response_obj[:body] = self.response_body self end private + def action_methods + self.class.action_methods + end + + def action_method?(action) + action_methods.include?(action) + end + + # It is possible for respond_to?(action_name) to be false and + # respond_to?(:action_missing) to be false if respond_to_action? + # is overridden in a subclass. For instance, ActionController::Base + # overrides it to include the case where a template matching the + # action_name is found. def process_action - respond_to?(action_name) ? send(action_name) : send(:action_missing, action_name) + if action_method?(action_name) then send(action_name) + elsif respond_to?(:action_missing, true) then action_missing(action_name) + end end + # Override this to change the conditions that will raise an + # ActionNotFound error. If you accept a difference case, + # you must handle it by also overriding process_action and + # handling the case. def respond_to_action?(action_name) - respond_to?(action_name) || respond_to?(:action_missing, true) + action_method?(action_name) || respond_to?(:action_missing, true) end - end end
\ No newline at end of file diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index c8b509081c..3aff83a209 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -1,10 +1,13 @@ module AbstractController module Callbacks - setup do - include ActiveSupport::NewCallbacks - define_callbacks :process_action + extend ActiveSupport::DependencyModule + + depends_on ActiveSupport::NewCallbacks + + included do + define_callbacks :process_action, "response_body" end - + def process_action _run_process_action_callbacks(action_name) do super @@ -14,11 +17,11 @@ module AbstractController module ClassMethods def _normalize_callback_options(options) if only = options[:only] - only = Array(only).map {|o| "action_name == :#{o}"}.join(" || ") + only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ") options[:per_key] = {:if => only} end if except = options[:except] - except = Array(except).map {|e| "action_name == :#{e}"}.join(" || ") + except = Array(except).map {|e| "action_name == '#{e}'"}.join(" || ") options[:per_key] = {:unless => except} end end diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb index 1f0b38417b..968d3080c1 100644 --- a/actionpack/lib/action_controller/abstract/helpers.rb +++ b/actionpack/lib/action_controller/abstract/helpers.rb @@ -1,19 +1,14 @@ module AbstractController module Helpers + extend ActiveSupport::DependencyModule + depends_on Renderer - - setup do + + included do extlib_inheritable_accessor :master_helper_module self.master_helper_module = Module.new end - - # def self.included(klass) - # klass.class_eval do - # extlib_inheritable_accessor :master_helper_module - # self.master_helper_module = Module.new - # end - # end - + def _action_view @_action_view ||= begin av = super diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 0039e67c5a..35d5e85ed9 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -1,8 +1,9 @@ module AbstractController module Layouts - + extend ActiveSupport::DependencyModule + depends_on Renderer - + module ClassMethods def layout(layout) unless [String, Symbol, FalseClass, NilClass].include?(layout.class) @@ -50,13 +51,16 @@ module AbstractController end def _render_template(template, options) - _action_view._render_template_with_layout(template, options[:_layout]) + _action_view._render_template_from_controller(template, options[:_layout], options, options[:_partial]) end private def _layout() end # This will be overwritten + # :api: plugin + # ==== + # Override this to mutate the inbound layout name def _layout_for_name(name) unless [String, FalseClass, NilClass].include?(name.class) raise ArgumentError, "String, false, or nil expected; you passed #{name.inspect}" @@ -67,10 +71,10 @@ module AbstractController def _default_layout(require_layout = false) if require_layout && !_layout - raise ArgumentError, + raise ArgumentError, "There was no default layout for #{self.class} in #{view_paths.inspect}" end - + begin layout = _layout_for_name(_layout) rescue NameError => e diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index 4117369bd4..750a5c9fb6 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -1,7 +1,44 @@ +require 'active_support/core_ext/class/attribute_accessors' + module AbstractController module Logger - setup do + extend ActiveSupport::DependencyModule + + class DelayedLog + def initialize(&blk) + @blk = blk + end + + def to_s + @blk.call + end + alias to_str to_s + end + + included do cattr_accessor :logger end + + def process(action) + ret = super + + if logger + log = DelayedLog.new do + "\n\nProcessing #{self.class.name}\##{action_name} " \ + "to #{request.formats} " \ + "(for #{request_origin}) [#{request.method.to_s.upcase}]" + end + + logger.info(log) + end + + ret + end + + def request_origin + # this *needs* to be cached! + # otherwise you'd get different results if calling it more than once + @request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}" + end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index e31accbbfc..f2044a35ec 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -2,22 +2,28 @@ require "action_controller/abstract/logger" module AbstractController module Renderer + extend ActiveSupport::DependencyModule + depends_on AbstractController::Logger - - setup do + + included do attr_internal :formats - + extlib_inheritable_accessor :_view_paths - + self._view_paths ||= ActionView::PathSet.new end - + def _action_view @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) end - def render(options = {}) - self.response_body = render_to_body(options) + def render(*args) + if response_body + raise AbstractController::DoubleRenderError, "OMG" + end + + self.response_body = render_to_body(*args) end # Raw rendering of a template to a Rack-compatible body. @@ -28,9 +34,16 @@ module AbstractController # :api: plugin def render_to_body(options = {}) name = options[:_template_name] || action_name - - template = options[:_template] || view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix]) - _render_template(template, options) + + # TODO: Refactor so we can just use the normal template logic for this + if options[:_partial_object] + _action_view._render_partial_from_controller(options) + else + options[:_template] ||= view_paths.find_by_parts(name.to_s, {:formats => formats}, + options[:_prefix], options[:_partial]) + + _render_template(options[:_template], options) + end end # Raw rendering of a template to a string. @@ -44,7 +57,7 @@ module AbstractController end def _render_template(template, options) - _action_view._render_template_with_layout(template) + _action_view._render_template_from_controller(template, nil, options, options[:_partial]) end def view_paths() _view_paths end |
