diff options
Diffstat (limited to 'actionpack/lib/action_controller')
19 files changed, 228 insertions, 115 deletions
diff --git a/actionpack/lib/action_controller/abstract.rb b/actionpack/lib/action_controller/abstract.rb index 3f5c4a185f..48e33282ec 100644 --- a/actionpack/lib/action_controller/abstract.rb +++ b/actionpack/lib/action_controller/abstract.rb @@ -1,3 +1,6 @@ +require "active_support/core_ext/module/attr_internal" +require "active_support/core_ext/module/delegation" + module AbstractController autoload :Base, "action_controller/abstract/base" autoload :Callbacks, "action_controller/abstract/callbacks" diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index 4b8d953643..1f2f096dae 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -25,6 +25,15 @@ module AbstractController 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 @@ -60,12 +69,13 @@ module AbstractController end def process(action_name) - unless respond_to_action?(action_name) + @_action_name = action_name = action_name.to_s + + unless action_name = method_for_action(action_name) raise ActionNotFound, "The action '#{action_name}' could not be found" end - - @_action_name = action_name - process_action + + process_action(action_name) self end @@ -75,23 +85,31 @@ module AbstractController 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 - if respond_to?(action_name) then send(action_name) - elsif respond_to?(:action_missing, true) then action_missing(action_name) - end + def process_action(method_name) + send(method_name) end - + + def _handle_action_missing + action_missing(@_action_name) + 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) - action_methods.include?(action_name.to_s) || respond_to?(:action_missing, true) + def method_for_action(action_name) + if action_method?(action_name) then action_name + elsif respond_to?(:action_missing, true) then "_handle_action_missing" + end end 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 3aff83a209..51b968c694 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -8,8 +8,8 @@ module AbstractController define_callbacks :process_action, "response_body" end - def process_action - _run_process_action_callbacks(action_name) do + def process_action(method_name) + _run_process_action_callbacks(method_name) do super end end diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index b154be754b..750a5c9fb6 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -4,8 +4,41 @@ module AbstractController module Logger 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 diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb index 2813e71d12..c59068c628 100644 --- a/actionpack/lib/action_controller/base/base.rb +++ b/actionpack/lib/action_controller/base/base.rb @@ -368,9 +368,8 @@ module ActionController #:nodoc: attr_reader :template def action(name, env) - # HACK: For global rescue to have access to the original request and response - request = env["action_controller.rescue.request"] ||= ActionDispatch::Request.new(env) - response = env["action_controller.rescue.response"] ||= ActionDispatch::Response.new + request = ActionDispatch::Request.new(env) + response = ActionDispatch::Response.new self.action_name = name && name.to_s process(request, response).to_a end diff --git a/actionpack/lib/action_controller/base/chained/filters.rb b/actionpack/lib/action_controller/base/chained/filters.rb index 9022b8b279..e121c0129d 100644 --- a/actionpack/lib/action_controller/base/chained/filters.rb +++ b/actionpack/lib/action_controller/base/chained/filters.rb @@ -160,7 +160,7 @@ module ActionController #:nodoc: def convert_only_and_except_options_to_sets_of_strings(opts) [:only, :except].each do |key| if values = opts[key] - opts[key] = Array(values).map(&:to_s).to_set + opts[key] = Array(values).map {|val| val.to_s }.to_set end end end @@ -571,12 +571,7 @@ module ActionController #:nodoc: # Returns an array of Filter objects for this controller. def filter_chain - if chain = read_inheritable_attribute('filter_chain') - return chain - else - write_inheritable_attribute('filter_chain', FilterChain.new) - return filter_chain - end + read_inheritable_attribute('filter_chain') || write_inheritable_attribute('filter_chain', FilterChain.new) end # Returns all the before filters for this class and all its ancestors. diff --git a/actionpack/lib/action_controller/base/http_authentication.rb b/actionpack/lib/action_controller/base/http_authentication.rb index fa8ecea408..2893290efb 100644 --- a/actionpack/lib/action_controller/base/http_authentication.rb +++ b/actionpack/lib/action_controller/base/http_authentication.rb @@ -194,9 +194,10 @@ module ActionController if valid_nonce && realm == credentials[:realm] && opaque == credentials[:opaque] password = password_procedure.call(credentials[:username]) + method = request.env['rack.methodoverride.original_method'] || request.env['REQUEST_METHOD'] [true, false].any? do |password_is_ha1| - expected = expected_response(request.env['REQUEST_METHOD'], request.env['REQUEST_URI'], credentials, password, password_is_ha1) + expected = expected_response(method, request.env['REQUEST_URI'], credentials, password, password_is_ha1) expected == credentials[:response] end end diff --git a/actionpack/lib/action_controller/dispatch/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb index 63866caed9..9ad1cadfd3 100644 --- a/actionpack/lib/action_controller/dispatch/dispatcher.rb +++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb @@ -1,87 +1,65 @@ +require 'active_support/core_ext/module/delegation' + module ActionController # Dispatches requests to the appropriate controller and takes care of # reloading the app after each request when Dependencies.load? is true. class Dispatcher + cattr_accessor :prepare_each_request + self.prepare_each_request = false + + cattr_accessor :router + self.router = Routing::Routes + + cattr_accessor :middleware + self.middleware = ActionDispatch::MiddlewareStack.new do |middleware| + middlewares = File.join(File.dirname(__FILE__), "middlewares.rb") + middleware.instance_eval(File.read(middlewares), middlewares, 1) + end + class << self def define_dispatcher_callbacks(cache_classes) unless cache_classes + # Run prepare callbacks before every request in development mode + self.prepare_each_request = true + # Development mode callbacks - before_dispatch :reload_application - after_dispatch :cleanup_application + ActionDispatch::Callbacks.before_dispatch do |app| + ActionController::Dispatcher.router.reload + end + + ActionDispatch::Callbacks.after_dispatch do + # Cleanup the application before processing the current request. + ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord) + ActiveSupport::Dependencies.clear + ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord) + end ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false end if defined?(ActiveRecord) - to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers } + to_prepare(:activerecord_instantiate_observers) do + ActiveRecord::Base.instantiate_observers + end end - after_dispatch :flush_logger if Base.logger && Base.logger.respond_to?(:flush) + if Base.logger && Base.logger.respond_to?(:flush) + after_dispatch do + Base.logger.flush + end + end to_prepare do I18n.reload! end end - # Add a preparation callback. Preparation callbacks are run before every - # request in development mode, and before the first request in production - # mode. - # - # An optional identifier may be supplied for the callback. If provided, - # to_prepare may be called again with the same identifier to replace the - # existing callback. Passing an identifier is a suggested practice if the - # code adding a preparation block may be reloaded. - def to_prepare(identifier = nil, &block) - @prepare_dispatch_callbacks ||= ActiveSupport::Callbacks::CallbackChain.new - callback = ActiveSupport::Callbacks::Callback.new(:prepare_dispatch, block, :identifier => identifier) - @prepare_dispatch_callbacks.replace_or_append!(callback) - end + delegate :to_prepare, :prepare_dispatch, :before_dispatch, :after_dispatch, + :to => ActionDispatch::Callbacks - def run_prepare_callbacks - new.send :run_callbacks, :prepare_dispatch + def new + @@middleware.build(@@router) end end - - cattr_accessor :router - self.router = Routing::Routes - - cattr_accessor :middleware - self.middleware = ActionDispatch::MiddlewareStack.new do |middleware| - middlewares = File.join(File.dirname(__FILE__), "middlewares.rb") - middleware.instance_eval(File.read(middlewares), middlewares, 1) - end - - include ActiveSupport::Callbacks - define_callbacks :prepare_dispatch, :before_dispatch, :after_dispatch - - def initialize - @app = @@middleware.build(@@router) - freeze - end - - def call(env) - run_callbacks :before_dispatch - @app.call(env) - ensure - run_callbacks :after_dispatch, :enumerator => :reverse_each - end - - def reload_application - # Run prepare callbacks before every request in development mode - run_callbacks :prepare_dispatch - - @@router.reload - end - - def cleanup_application - # Cleanup the application before processing the current request. - ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord) - ActiveSupport::Dependencies.clear - ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord) - end - - def flush_logger - Base.logger.flush - end end end diff --git a/actionpack/lib/action_controller/dispatch/middlewares.rb b/actionpack/lib/action_controller/dispatch/middlewares.rb index f99637b109..b25ed3fd3f 100644 --- a/actionpack/lib/action_controller/dispatch/middlewares.rb +++ b/actionpack/lib/action_controller/dispatch/middlewares.rb @@ -2,10 +2,11 @@ use "Rack::Lock", :if => lambda { !ActionController::Base.allow_concurrency } -use "ActionDispatch::Failsafe" use "ActionDispatch::ShowExceptions", lambda { ActionController::Base.consider_all_requests_local } +use "ActionDispatch::Callbacks", lambda { ActionController::Dispatcher.prepare_each_request } use "ActionDispatch::Rescue", lambda { controller = (::ApplicationController rescue ActionController::Base) + # TODO: Replace with controller.action(:_rescue_action) controller.method(:rescue_action) } diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 1f215bb6f1..bc47713529 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -7,6 +7,7 @@ module ActionController autoload :Rails2Compatibility, "action_controller/new_base/compatibility" autoload :Redirector, "action_controller/new_base/redirector" autoload :Renderer, "action_controller/new_base/renderer" + autoload :Rescue, "action_controller/new_base/rescuable" autoload :Testing, "action_controller/new_base/testing" autoload :UrlFor, "action_controller/new_base/url_for" diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index 1adcc9c71f..c25ffd5c84 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -12,14 +12,40 @@ module ActionController include ActionController::Renderer include ActionController::Layouts include ActionController::ConditionalGet - + # Legacy modules include SessionManagement include ActionDispatch::StatusCodes - + # Rails 2.x compatibility include ActionController::Rails2Compatibility - + + # TODO: Extract into its own module + # This should be moved together with other normalizing behavior + module ImplicitRender + def process_action(method_name) + ret = super + render if response_body.nil? + ret + end + + def _implicit_render + render + end + + def method_for_action(action_name) + super || begin + if view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path) + "_implicit_render" + end + end + end + end + + include ImplicitRender + + include ActionController::Rescue + def self.inherited(klass) ::ActionController::Base.subclasses << klass.to_s super @@ -113,15 +139,5 @@ module ActionController super(url, status) end - - def process_action - ret = super - render if response_body.nil? - ret - end - - def respond_to_action?(action_name) - super || view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path) - end end end
\ No newline at end of file diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index d17f498b60..0a283887b6 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -42,6 +42,17 @@ module ActionController # Controls the resource action separator cattr_accessor :resource_action_separator self.resource_action_separator = "/" + + cattr_accessor :use_accept_header + self.use_accept_header = true + + cattr_accessor :page_cache_directory + self.page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : "" + + cattr_reader :cache_store + + cattr_accessor :consider_all_requests_local + self.consider_all_requests_local = true end module ClassMethods @@ -50,6 +61,11 @@ module ActionController def rescue_action(env) raise env["action_dispatch.rescue.exception"] end + + # Defines the storage option for cached fragments + def cache_store=(store_option) + @@cache_store = ActiveSupport::Cache.lookup_store(store_option) + end end def initialize(*) @@ -66,6 +82,14 @@ module ActionController super end + + def _handle_method_missing + method_missing(@_action_name.to_sym) + end + + def method_for_action(action_name) + super || (respond_to?(:method_missing) && "_handle_method_missing") + end def _layout_for_name(name) name &&= name.sub(%r{^/?layouts/}, '') diff --git a/actionpack/lib/action_controller/new_base/hide_actions.rb b/actionpack/lib/action_controller/new_base/hide_actions.rb index d1857a9169..a29b09a893 100644 --- a/actionpack/lib/action_controller/new_base/hide_actions.rb +++ b/actionpack/lib/action_controller/new_base/hide_actions.rb @@ -12,8 +12,8 @@ module ActionController private - def respond_to_action?(action_name) - !hidden_actions.include?(action_name) && (super || respond_to?(:method_missing)) + def action_method?(action_name) + !hidden_actions.include?(action_name) && super end module ClassMethods diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index 6852eb200a..8891a2a8c3 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -24,11 +24,6 @@ module ActionController # :api: public def controller_path() self.class.controller_path end - # :api: private - def self.internal_methods - ActionController::Http.public_instance_methods(true) - end - # :api: private def self.action_names() action_methods end @@ -53,8 +48,6 @@ module ActionController @_response = ActionDispatch::Response.new @_response.request = request process(name) - @_response.body = response_body - @_response.prepare! to_rack end @@ -67,6 +60,8 @@ module ActionController # :api: private def to_rack + @_response.body = response_body + @_response.prepare! @_response.to_a end end diff --git a/actionpack/lib/action_controller/new_base/rescuable.rb b/actionpack/lib/action_controller/new_base/rescuable.rb new file mode 100644 index 0000000000..29ffe19d5f --- /dev/null +++ b/actionpack/lib/action_controller/new_base/rescuable.rb @@ -0,0 +1,53 @@ +module ActionController #:nodoc: + # Actions that fail to perform as expected throw exceptions. These + # exceptions can either be rescued for the public view (with a nice + # user-friendly explanation) or for the developers view (with tons of + # debugging information). The developers view is already implemented by + # the Action Controller, but the public view should be tailored to your + # specific application. + # + # The default behavior for public exceptions is to render a static html + # file with the name of the error code thrown. If no such file exists, an + # empty response is sent with the correct status code. + # + # You can override what constitutes a local request by overriding the + # <tt>local_request?</tt> method in your own controller. Custom rescue + # behavior is achieved by overriding the <tt>rescue_action_in_public</tt> + # and <tt>rescue_action_locally</tt> methods. + module Rescue + extend ActiveSupport::DependencyModule + + included do + include ActiveSupport::Rescuable + end + + module ClassMethods + # This can be removed once we can move action(:_rescue_action) into middlewares.rb + # Currently, it does controller.method(:rescue_action), which is hiding the implementation + # difference between the old and new base. + def rescue_action(env) + action(:_rescue_action).call(env) + end + end + + attr_internal :rescued_exception + + private + + def method_for_action(action_name) + return action_name if self.rescued_exception = request.env.delete("action_dispatch.rescue.exception") + super + end + + def _rescue_action + rescue_with_handler(rescued_exception) || raise(rescued_exception) + end + + def process_action(*) + super + rescue Exception => exception + self.rescued_exception = exception + _rescue_action + end + end +end diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index 106990b9ba..b39d8d539d 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -7,7 +7,7 @@ module ActionController @_response = response @_response.request = request ret = process(request.parameters[:action]) - @_response.body = self.response_body + @_response.body = self.response_body || " " @_response.prepare! set_test_assigns ret diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb index 7edd379bc0..ce59866531 100644 --- a/actionpack/lib/action_controller/routing.rb +++ b/actionpack/lib/action_controller/routing.rb @@ -4,7 +4,6 @@ require 'set' require 'active_support/core_ext/module/aliasing' require 'active_support/core_ext/module/attribute_accessors' - require 'action_controller/routing/optimisations' require 'action_controller/routing/routing_ext' require 'action_controller/routing/route' diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 8f4358c33e..8831ff57e2 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -132,9 +132,6 @@ module ActionController #:nodoc: @request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash build_request_uri(action, parameters) - @request.env["action_controller.rescue.request"] = @request - @request.env["action_controller.rescue.response"] = @response - Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest env = @request.env diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb index ae20f9947c..a992f7d912 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb @@ -73,7 +73,7 @@ module HTML # Specifies the default Set of tags that the #sanitize helper will allow unscathed. self.allowed_tags = Set.new(%w(strong em b i p code pre tt samp kbd var sub - sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dt dd abbr + sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dl dt dd abbr acronym a img blockquote del ins)) # Specifies the default Set of html attributes that the #sanitize helper will leave |