aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_controller')
-rw-r--r--actionpack/lib/action_controller/abstract.rb3
-rw-r--r--actionpack/lib/action_controller/abstract/base.rb52
-rw-r--r--actionpack/lib/action_controller/abstract/callbacks.rb6
-rw-r--r--actionpack/lib/action_controller/abstract/layouts.rb2
-rw-r--r--actionpack/lib/action_controller/abstract/logger.rb37
-rw-r--r--actionpack/lib/action_controller/abstract/renderer.rb29
-rw-r--r--actionpack/lib/action_controller/base/base.rb7
-rw-r--r--actionpack/lib/action_controller/base/chained/benchmarking.rb2
-rw-r--r--actionpack/lib/action_controller/base/chained/filters.rb9
-rw-r--r--actionpack/lib/action_controller/base/http_authentication.rb6
-rw-r--r--actionpack/lib/action_controller/base/layout.rb4
-rw-r--r--actionpack/lib/action_controller/base/redirect.rb4
-rw-r--r--actionpack/lib/action_controller/dispatch/dispatcher.rb100
-rw-r--r--actionpack/lib/action_controller/dispatch/middlewares.rb3
-rw-r--r--actionpack/lib/action_controller/new_base.rb2
-rw-r--r--actionpack/lib/action_controller/new_base/base.rb121
-rw-r--r--actionpack/lib/action_controller/new_base/compatibility.rb66
-rw-r--r--actionpack/lib/action_controller/new_base/hide_actions.rb4
-rw-r--r--actionpack/lib/action_controller/new_base/http.rb20
-rw-r--r--actionpack/lib/action_controller/new_base/layouts.rb2
-rw-r--r--actionpack/lib/action_controller/new_base/redirector.rb19
-rw-r--r--actionpack/lib/action_controller/new_base/renderer.rb27
-rw-r--r--actionpack/lib/action_controller/new_base/rescuable.rb53
-rw-r--r--actionpack/lib/action_controller/new_base/testing.rb2
-rw-r--r--actionpack/lib/action_controller/record_identifier.rb2
-rw-r--r--actionpack/lib/action_controller/routing.rb4
-rw-r--r--actionpack/lib/action_controller/routing/builder.rb2
-rw-r--r--actionpack/lib/action_controller/routing/route.rb8
-rw-r--r--actionpack/lib/action_controller/testing/process.rb14
-rw-r--r--actionpack/lib/action_controller/testing/process2.rb1
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb2
31 files changed, 445 insertions, 168 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 ab9aed0b26..1f2f096dae 100644
--- a/actionpack/lib/action_controller/abstract/base.rb
+++ b/actionpack/lib/action_controller/abstract/base.rb
@@ -1,4 +1,16 @@
+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
@@ -13,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
@@ -48,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
@@ -63,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) || 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 \ 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 6e15b3e81b..51b968c694 100644
--- a/actionpack/lib/action_controller/abstract/callbacks.rb
+++ b/actionpack/lib/action_controller/abstract/callbacks.rb
@@ -5,11 +5,11 @@ module AbstractController
depends_on ActiveSupport::NewCallbacks
included do
- define_callbacks :process_action
+ 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/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb
index e48b8b2b4b..35d5e85ed9 100644
--- a/actionpack/lib/action_controller/abstract/layouts.rb
+++ b/actionpack/lib/action_controller/abstract/layouts.rb
@@ -51,7 +51,7 @@ module AbstractController
end
def _render_template(template, options)
- _action_view._render_template_with_layout(template, options[:_layout], options)
+ _action_view._render_template_from_controller(template, options[:_layout], options, options[:_partial])
end
private
diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb
index 5fb78f1755..750a5c9fb6 100644
--- a/actionpack/lib/action_controller/abstract/logger.rb
+++ b/actionpack/lib/action_controller/abstract/logger.rb
@@ -1,9 +1,44 @@
+require 'active_support/core_ext/class/attribute_accessors'
+
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 \ 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 b58688c9da..f2044a35ec 100644
--- a/actionpack/lib/action_controller/abstract/renderer.rb
+++ b/actionpack/lib/action_controller/abstract/renderer.rb
@@ -1,15 +1,6 @@
require "action_controller/abstract/logger"
module AbstractController
- class AbstractControllerError < StandardError; end
- class DoubleRenderError < AbstractControllerError
- 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
-
module Renderer
extend ActiveSupport::DependencyModule
@@ -27,12 +18,12 @@ module AbstractController
@_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self)
end
- def render(options = {})
+ def render(*args)
if response_body
raise AbstractController::DoubleRenderError, "OMG"
end
- self.response_body = render_to_body(options)
+ self.response_body = render_to_body(*args)
end
# Raw rendering of a template to a Rack-compatible body.
@@ -43,10 +34,16 @@ module AbstractController
# :api: plugin
def render_to_body(options = {})
name = options[:_template_name] || action_name
-
- options[:_template] ||= view_paths.find_by_parts(name.to_s, {:formats => formats}, options[:_prefix])
-
- _render_template(options[:_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.
@@ -60,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
diff --git a/actionpack/lib/action_controller/base/base.rb b/actionpack/lib/action_controller/base/base.rb
index d25801b17b..c59068c628 100644
--- a/actionpack/lib/action_controller/base/base.rb
+++ b/actionpack/lib/action_controller/base/base.rb
@@ -1,5 +1,7 @@
require 'action_controller/deprecated'
require 'set'
+require 'active_support/core_ext/class/inheritable_attributes'
+require 'active_support/core_ext/module/attr_internal'
module ActionController #:nodoc:
class ActionControllerError < StandardError #:nodoc:
@@ -366,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/benchmarking.rb b/actionpack/lib/action_controller/base/chained/benchmarking.rb
index 066150f58a..66e9e9c31d 100644
--- a/actionpack/lib/action_controller/base/chained/benchmarking.rb
+++ b/actionpack/lib/action_controller/base/chained/benchmarking.rb
@@ -1,4 +1,4 @@
-require 'benchmark'
+require 'active_support/core_ext/benchmark'
module ActionController #:nodoc:
# The benchmarking module times the performance of actions and reports to the logger. If the Active Record
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 b6b5267c66..fa8ecea408 100644
--- a/actionpack/lib/action_controller/base/http_authentication.rb
+++ b/actionpack/lib/action_controller/base/http_authentication.rb
@@ -1,3 +1,5 @@
+require 'active_support/base64'
+
module ActionController
module HttpAuthentication
# Makes it dead easy to do HTTP Basic authentication.
@@ -276,7 +278,7 @@ module ActionController
t = time.to_i
hashed = [t, secret_key]
digest = ::Digest::MD5.hexdigest(hashed.join(":"))
- Base64.encode64("#{t}:#{digest}").gsub("\n", '')
+ ActiveSupport::Base64.encode64("#{t}:#{digest}").gsub("\n", '')
end
# Might want a shorter timeout depending on whether the request
@@ -285,7 +287,7 @@ module ActionController
# allow a user to use new nonce without prompting user again for their
# username and password.
def validate_nonce(request, value, seconds_to_timeout=5*60)
- t = Base64.decode64(value).split(":").first.to_i
+ t = ActiveSupport::Base64.decode64(value).split(":").first.to_i
nonce(t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
end
diff --git a/actionpack/lib/action_controller/base/layout.rb b/actionpack/lib/action_controller/base/layout.rb
index 1ad5191c73..cf5f46a32b 100644
--- a/actionpack/lib/action_controller/base/layout.rb
+++ b/actionpack/lib/action_controller/base/layout.rb
@@ -1,3 +1,7 @@
+require 'active_support/core_ext/enumerable'
+require 'active_support/core_ext/class/delegating_attributes'
+require 'active_support/core_ext/class/inheritable_attributes'
+
module ActionController #:nodoc:
module Layout #:nodoc:
def self.included(base)
diff --git a/actionpack/lib/action_controller/base/redirect.rb b/actionpack/lib/action_controller/base/redirect.rb
index 4849caac0a..7e10f614e2 100644
--- a/actionpack/lib/action_controller/base/redirect.rb
+++ b/actionpack/lib/action_controller/base/redirect.rb
@@ -70,7 +70,9 @@ module ActionController
def redirect_to_full_url(url, status)
raise DoubleRenderError if performed?
logger.info("Redirected to #{url}") if logger && logger.info?
- response.redirect(url, interpret_status(status))
+ response.status = interpret_status(status)
+ response.location = url.gsub(/[\r\n]/, '')
+ response.body = "<html><body>You are being <a href=\"#{CGI.escapeHTML(url)}\">redirected</a>.</body></html>"
@performed_redirect = true
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 8a7de1476c..bc47713529 100644
--- a/actionpack/lib/action_controller/new_base.rb
+++ b/actionpack/lib/action_controller/new_base.rb
@@ -5,7 +5,9 @@ module ActionController
autoload :Http, "action_controller/new_base/http"
autoload :Layouts, "action_controller/new_base/layouts"
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 4892886341..c25ffd5c84 100644
--- a/actionpack/lib/action_controller/new_base/base.rb
+++ b/actionpack/lib/action_controller/new_base/base.rb
@@ -8,17 +8,44 @@ module ActionController
include ActionController::HideActions
include ActionController::UrlFor
+ include ActionController::Redirector
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
@@ -34,29 +61,83 @@ module ActionController
end
end
- def render(action = action_name, options = {})
+ def render_to_body(action = nil, options = {})
if action.is_a?(Hash)
options, action = action, nil
- else
- options.merge! :action => action
+ elsif action.is_a?(String) || action.is_a?(Symbol)
+ key = case action = action.to_s
+ when %r{^/} then :file
+ when %r{/} then :template
+ else :action
+ end
+ options.merge! key => action
+ elsif action
+ options.merge! :partial => action
end
- super(options)
- end
-
- def render_to_body(options = {})
- options = {:template => options} if options.is_a?(String)
- super
- end
-
- def process_action
- ret = super
- render if response_body.nil?
- ret
+ if options.key?(:action) && options[:action].to_s.index("/")
+ options[:template] = options.delete(:action)
+ end
+
+ # options = {:template => options.to_s} if options.is_a?(String) || options.is_a?(Symbol)
+ super(options) || " "
end
- def respond_to_action?(action_name)
- super || view_paths.find_by_parts?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path)
+ # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
+ #
+ # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
+ # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
+ # * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
+ # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
+ # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
+ # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
+ #
+ # Examples:
+ # redirect_to :action => "show", :id => 5
+ # redirect_to post
+ # redirect_to "http://www.rubyonrails.org"
+ # redirect_to "/images/screenshot.jpg"
+ # redirect_to articles_url
+ # redirect_to :back
+ #
+ # The redirection happens as a "302 Moved" header unless otherwise specified.
+ #
+ # Examples:
+ # redirect_to post_url(@post), :status=>:found
+ # redirect_to :action=>'atom', :status=>:moved_permanently
+ # redirect_to post_url(@post), :status=>301
+ # redirect_to :action=>'atom', :status=>302
+ #
+ # When using <tt>redirect_to :back</tt>, if there is no referrer,
+ # RedirectBackError will be raised. You may specify some fallback
+ # behavior for this case by rescuing RedirectBackError.
+ def redirect_to(options = {}, response_status = {}) #:doc:
+ raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
+
+ status = if options.is_a?(Hash) && options.key?(:status)
+ interpret_status(options.delete(:status))
+ elsif response_status.key?(:status)
+ interpret_status(response_status[:status])
+ else
+ 302
+ end
+
+ url = case options
+ # The scheme name consist of a letter followed by any combination of
+ # letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
+ # characters; and is terminated by a colon (":").
+ when %r{^\w[\w\d+.-]*:.*}
+ options
+ when String
+ request.protocol + request.host_with_port + options
+ when :back
+ raise RedirectBackError unless refer = request.headers["Referer"]
+ refer
+ else
+ url_for(options)
+ end
+
+ super(url, status)
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 4655a94923..0a283887b6 100644
--- a/actionpack/lib/action_controller/new_base/compatibility.rb
+++ b/actionpack/lib/action_controller/new_base/compatibility.rb
@@ -8,27 +8,51 @@ module ActionController
::ActionController::DoubleRenderError = ::AbstractController::DoubleRenderError
cattr_accessor :session_options
- self.send(:class_variable_set, "@@session_options", {})
+ self.session_options = {}
cattr_accessor :allow_concurrency
- self.send(:class_variable_set, "@@allow_concurrency", false)
+ self.allow_concurrency = false
cattr_accessor :param_parsers
- self.send(:class_variable_set, "@@param_parsers", { Mime::MULTIPART_FORM => :multipart_form,
- Mime::URL_ENCODED_FORM => :url_encoded_form,
- Mime::XML => :xml_simple,
- Mime::JSON => :json })
+ self.param_parsers = { Mime::MULTIPART_FORM => :multipart_form,
+ Mime::URL_ENCODED_FORM => :url_encoded_form,
+ Mime::XML => :xml_simple,
+ Mime::JSON => :json }
cattr_accessor :relative_url_root
- self.send(:class_variable_set, "@@relative_url_root", ENV['RAILS_RELATIVE_URL_ROOT'])
+ self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT']
cattr_accessor :default_charset
- self.send(:class_variable_set, "@@default_charset", "utf-8")
+ self.default_charset = "utf-8"
- cattr_reader :protected_instance_variables
- self.send(:class_variable_set, "@@protected_instance_variables", %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller
+ # cattr_reader :protected_instance_variables
+ cattr_accessor :protected_instance_variables
+ self.protected_instance_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller
@action_name @before_filter_chain_aborted @action_cache_path @_headers @_params
- @_flash @_response))
+ @_flash @_response)
+
+ # Indicates whether or not optimise the generated named
+ # route helper methods
+ cattr_accessor :optimise_named_routes
+ self.optimise_named_routes = true
+
+ cattr_accessor :resources_path_names
+ self.resources_path_names = { :new => 'new', :edit => 'edit' }
+
+ # 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
@@ -37,8 +61,18 @@ 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(*)
+ super
+ @template = _action_view
+ end
+
def render_to_body(options)
if options.is_a?(Hash) && options.key?(:template)
options[:template].sub!(/^\//, '')
@@ -48,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 f269fe70db..8891a2a8c3 100644
--- a/actionpack/lib/action_controller/new_base/http.rb
+++ b/actionpack/lib/action_controller/new_base/http.rb
@@ -1,3 +1,6 @@
+require 'action_controller/abstract'
+require 'active_support/core_ext/module/delegation'
+
module ActionController
class Http < AbstractController::Base
abstract!
@@ -21,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
@@ -38,26 +36,32 @@ module ActionController
controller.call(env).to_rack
end
+ delegate :headers, :to => "@_response"
+
+ def params
+ @_params ||= @_request.parameters
+ end
+
# :api: private
def call(name, env)
@_request = ActionDispatch::Request.new(env)
@_response = ActionDispatch::Response.new
@_response.request = request
process(name)
- @_response.body = response_body
- @_response.prepare!
to_rack
end
def self.action(name)
@actions ||= {}
- @actions[name] ||= proc do |env|
+ @actions[name.to_s] ||= proc do |env|
new.call(name, env)
end
end
# :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/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb
index e851eb5f9a..bf5b14c4e1 100644
--- a/actionpack/lib/action_controller/new_base/layouts.rb
+++ b/actionpack/lib/action_controller/new_base/layouts.rb
@@ -15,7 +15,7 @@ module ActionController
# render :text => ..., :layout => ...
# or
# render :anything_else
- if (!options.key?(:text) && !options.key?(:inline)) || options.key?(:layout)
+ if (!options.key?(:text) && !options.key?(:inline) && !options.key?(:partial)) || options.key?(:layout)
options[:_layout] = options.key?(:layout) ? _layout_for_option(options[:layout]) : _default_layout
end
diff --git a/actionpack/lib/action_controller/new_base/redirector.rb b/actionpack/lib/action_controller/new_base/redirector.rb
new file mode 100644
index 0000000000..ff7b74341c
--- /dev/null
+++ b/actionpack/lib/action_controller/new_base/redirector.rb
@@ -0,0 +1,19 @@
+module ActionController
+ class RedirectBackError < AbstractController::Error #:nodoc:
+ DEFAULT_MESSAGE = 'No HTTP_REFERER was set in the request to this action, so redirect_to :back could not be called successfully. If this is a test, make sure to specify request.env["HTTP_REFERER"].'
+
+ def initialize(message = nil)
+ super(message || DEFAULT_MESSAGE)
+ end
+ end
+
+ module Redirector
+ def redirect_to(url, status) #:doc:
+ raise AbstractController::DoubleRenderError if response_body
+ logger.info("Redirected to #{url}") if logger && logger.info?
+ response.status = status
+ response.location = url.gsub(/[\r\n]/, '')
+ self.response_body = "<html><body>You are being <a href=\"#{CGI.escapeHTML(url)}\">redirected</a>.</body></html>"
+ end
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb
index 41e3dfbe23..8a9f230603 100644
--- a/actionpack/lib/action_controller/new_base/renderer.rb
+++ b/actionpack/lib/action_controller/new_base/renderer.rb
@@ -9,13 +9,9 @@ module ActionController
super
end
- def render(options = {})
+ def render_to_body(options)
_process_options(options)
- super(options)
- end
-
- def render_to_body(options)
if options.key?(:text)
options[:_template] = ActionView::TextTemplate.new(_text(options))
template = nil
@@ -25,12 +21,18 @@ module ActionController
options[:_template] = template
elsif options.key?(:template)
options[:_template_name] = options[:template]
+ elsif options.key?(:file)
+ options[:_template_name] = options[:file]
+ elsif options.key?(:partial)
+ _render_partial(options[:partial], options)
else
options[:_template_name] = (options[:action] || action_name).to_s
options[:_prefix] = _prefix
end
ret = super(options)
+
+ options[:_template] ||= _action_view._partial
response.content_type ||= options[:_template].mime_type
ret
end
@@ -49,6 +51,21 @@ module ActionController
else text.to_s
end
end
+
+ def _render_partial(partial, options)
+ case partial
+ when true
+ options[:_prefix] = _prefix
+ when String
+ options[:_prefix] = _prefix unless partial.index('/')
+ options[:_template_name] = partial
+ else
+ options[:_partial_object] = true
+ return
+ end
+
+ options[:_partial] = options[:object] || true
+ end
def _process_options(options)
status, content_type = options.values_at(:status, :content_type)
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/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb
index 6bda27e23a..b4408e4e1d 100644
--- a/actionpack/lib/action_controller/record_identifier.rb
+++ b/actionpack/lib/action_controller/record_identifier.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/module'
+
module ActionController
# The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or
# Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate
diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb
index c0eb61340b..ce59866531 100644
--- a/actionpack/lib/action_controller/routing.rb
+++ b/actionpack/lib/action_controller/routing.rb
@@ -1,5 +1,9 @@
require 'cgi'
require 'uri'
+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/routing/builder.rb b/actionpack/lib/action_controller/routing/builder.rb
index d9590c88b8..42ad12e1ea 100644
--- a/actionpack/lib/action_controller/routing/builder.rb
+++ b/actionpack/lib/action_controller/routing/builder.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/hash/except'
+
module ActionController
module Routing
class RouteBuilder #:nodoc:
diff --git a/actionpack/lib/action_controller/routing/route.rb b/actionpack/lib/action_controller/routing/route.rb
index e2077edad8..eba05a3c5a 100644
--- a/actionpack/lib/action_controller/routing/route.rb
+++ b/actionpack/lib/action_controller/routing/route.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/misc'
+
module ActionController
module Routing
class Route #:nodoc:
@@ -65,7 +67,7 @@ module ActionController
# map.connect '/page/:id', :controller => 'pages', :action => 'show', :id => /\d+/
#
def parameter_shell
- @parameter_shell ||= returning({}) do |shell|
+ @parameter_shell ||= {}.tap do |shell|
requirements.each do |key, requirement|
shell[key] = requirement unless requirement.is_a? Regexp
end
@@ -76,7 +78,7 @@ module ActionController
# includes keys that appear inside the path, and keys that have requirements
# placed upon them.
def significant_keys
- @significant_keys ||= returning([]) do |sk|
+ @significant_keys ||= [].tap do |sk|
segments.each { |segment| sk << segment.key if segment.respond_to? :key }
sk.concat requirements.keys
sk.uniq!
@@ -86,7 +88,7 @@ module ActionController
# Return a hash of key/value pairs representing the keys in the route that
# have defaults, or which are specified by non-regexp requirements.
def defaults
- @defaults ||= returning({}) do |hash|
+ @defaults ||= {}.tap do |hash|
segments.each do |segment|
next unless segment.respond_to? :default
hash[segment.key] = segment.default unless segment.default.nil?
diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb
index 21023ac101..8831ff57e2 100644
--- a/actionpack/lib/action_controller/testing/process.rb
+++ b/actionpack/lib/action_controller/testing/process.rb
@@ -1,4 +1,5 @@
require 'rack/session/abstract/id'
+require 'active_support/core_ext/object/conversions'
module ActionController #:nodoc:
class TestRequest < ActionDispatch::TestRequest #:nodoc:
@@ -131,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
@@ -161,11 +159,13 @@ module ActionController #:nodoc:
alias xhr :xml_http_request
def assigns(key = nil)
- if key.nil?
- @controller.template.assigns
- else
- @controller.template.assigns[key.to_s]
+ assigns = {}
+ @controller.instance_variable_names.each do |ivar|
+ next if ActionController::Base.protected_instance_variables.include?(ivar)
+ assigns[ivar[1..-1]] = @controller.instance_variable_get(ivar)
end
+
+ key.nil? ? assigns : assigns[key.to_s]
end
def session
diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb
index 18b7335450..e9a79369b9 100644
--- a/actionpack/lib/action_controller/testing/process2.rb
+++ b/actionpack/lib/action_controller/testing/process2.rb
@@ -50,6 +50,7 @@ module ActionController
@request.session = ActionController::TestSession.new(session) unless session.nil?
@request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash
build_request_uri(action, parameters)
+ @controller.request = @request
@controller.params.merge!(parameters)
# Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest
@controller.process_with_test(@request, @response)
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