aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/abstract_controller.rb18
-rw-r--r--actionpack/lib/abstract_controller/base.rb9
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb2
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb2
-rw-r--r--actionpack/lib/abstract_controller/logger.rb28
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb (renamed from actionpack/lib/abstract_controller/rendering_controller.rb)14
-rw-r--r--actionpack/lib/action_controller.rb114
-rw-r--r--actionpack/lib/action_controller/base.rb78
-rw-r--r--actionpack/lib/action_controller/caching.rb12
-rw-r--r--actionpack/lib/action_controller/metal.rb9
-rw-r--r--actionpack/lib/action_controller/metal/benchmarking.rb1
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb2
-rw-r--r--actionpack/lib/action_controller/metal/cookies.rb170
-rw-r--r--actionpack/lib/action_controller/metal/flash.rb41
-rw-r--r--actionpack/lib/action_controller/metal/head.rb7
-rw-r--r--actionpack/lib/action_controller/metal/layouts.rb2
-rw-r--r--actionpack/lib/action_controller/metal/logger.rb34
-rw-r--r--actionpack/lib/action_controller/metal/rack_delegation.rb (renamed from actionpack/lib/action_controller/metal/rack_convenience.rb)10
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb90
-rw-r--r--actionpack/lib/action_controller/metal/redirector.rb22
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb (renamed from actionpack/lib/action_controller/metal/render_options.rb)7
-rw-r--r--actionpack/lib/action_controller/metal/rendering.rb (renamed from actionpack/lib/action_controller/metal/rendering_controller.rb)4
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb32
-rw-r--r--actionpack/lib/action_controller/metal/session.rb15
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb2
-rw-r--r--actionpack/lib/action_controller/metal/testing.rb2
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb2
-rw-r--r--actionpack/lib/action_controller/metal/verification.rb70
-rw-r--r--actionpack/lib/action_controller/notifications.rb10
-rw-r--r--actionpack/lib/action_controller/rails.rb102
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner.rb26
-rw-r--r--actionpack/lib/action_dispatch.rb59
-rwxr-xr-xactionpack/lib/action_dispatch/http/request.rb11
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb29
-rw-r--r--actionpack/lib/action_dispatch/http/status_codes.rb25
-rw-r--r--actionpack/lib/action_dispatch/http/utils.rb20
-rw-r--r--actionpack/lib/action_dispatch/middleware/cascade.rb29
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb47
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb9
-rw-r--r--actionpack/lib/action_dispatch/middleware/show_exceptions.rb5
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb213
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb8
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/dom.rb4
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/response.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/selector.rb22
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/tag.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb4
-rw-r--r--actionpack/lib/action_view.rb43
-rw-r--r--actionpack/lib/action_view/helpers/sanitize_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb2
-rw-r--r--actionpack/lib/action_view/render/rendering.rb22
-rw-r--r--actionpack/lib/action_view/safe_buffer.rb1
-rw-r--r--actionpack/lib/action_view/template.rb29
-rw-r--r--actionpack/lib/action_view/template/handlers/erb.rb3
55 files changed, 899 insertions, 629 deletions
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index 109a3a3385..237ab577ba 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -1,20 +1,18 @@
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
-require 'active_support'
+require 'active_support/ruby/shim'
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
module AbstractController
extend ActiveSupport::Autoload
- deferrable do
- autoload :Base
- autoload :Callbacks
- autoload :Helpers
- autoload :Layouts
- autoload :LocalizedCache
- autoload :Logger
- autoload :RenderingController
- end
+ autoload :Base
+ autoload :Callbacks
+ autoload :Helpers
+ autoload :Layouts
+ autoload :LocalizedCache
+ autoload :Logger
+ autoload :Rendering
end
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index 905d04e20d..efea81aa71 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -5,6 +5,7 @@ module AbstractController
class Base
attr_internal :response_body
attr_internal :action_name
+ attr_internal :formats
class << self
attr_reader :abstract
@@ -83,7 +84,7 @@ module AbstractController
#
# ==== Returns
# self
- def process(action)
+ def process(action, *args)
@_action_name = action_name = action.to_s
unless action_name = method_for_action(action_name)
@@ -92,7 +93,7 @@ module AbstractController
@_response_body = nil
- process_action(action_name)
+ process_action(action_name, *args)
end
private
@@ -112,8 +113,8 @@ 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.
- def process_action(method_name)
- send_action(method_name)
+ def process_action(method_name, *args)
+ send_action(method_name, *args)
end
# Actually call the method associated with the action. Override
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index d3b492ad09..1d898d1a4c 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -4,7 +4,7 @@ module AbstractController
module Helpers
extend ActiveSupport::Concern
- include RenderingController
+ include Rendering
def self.next_serial
@helper_serial ||= 0
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index c71cef42b2..46760bba7c 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -2,7 +2,7 @@ module AbstractController
module Layouts
extend ActiveSupport::Concern
- include RenderingController
+ include Rendering
included do
extlib_inheritable_accessor(:_layout_conditions) { Hash.new }
diff --git a/actionpack/lib/abstract_controller/logger.rb b/actionpack/lib/abstract_controller/logger.rb
index 27ba5be45f..e3bcd28da7 100644
--- a/actionpack/lib/abstract_controller/logger.rb
+++ b/actionpack/lib/abstract_controller/logger.rb
@@ -29,33 +29,5 @@ module AbstractController
@str.send(*args, &block)
end
end
-
- # Override process_action in the AbstractController::Base
- # to log details about the method.
- def process_action(action)
- result = ActiveSupport::Notifications.instrument(:process_action,
- :controller => self, :action => action) do
- super
- end
-
- 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
-
- result
- end
-
- private
- # Returns the request origin with the IP and time. This needs to be cached,
- # otherwise we would get different results for each time it calls.
- def request_origin
- @request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}"
- end
end
end
diff --git a/actionpack/lib/abstract_controller/rendering_controller.rb b/actionpack/lib/abstract_controller/rendering.rb
index 7f2243d4ef..64a8a5f241 100644
--- a/actionpack/lib/abstract_controller/rendering_controller.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -10,13 +10,12 @@ module AbstractController
end
end
- module RenderingController
+ module Rendering
extend ActiveSupport::Concern
include AbstractController::Logger
included do
- attr_internal :formats
extlib_inheritable_accessor :_view_paths
self._view_paths ||= ActionView::PathSet.new
end
@@ -80,7 +79,7 @@ module AbstractController
#
# :api: plugin
def render_to_string(options = {})
- AbstractController::RenderingController.body_to_s(render_to_body(options))
+ AbstractController::Rendering.body_to_s(render_to_body(options))
end
# Renders the template from an object.
@@ -126,8 +125,8 @@ module AbstractController
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 #{options[:inline].inspect}", handler, {})
+ 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]
@@ -195,9 +194,8 @@ module AbstractController
# 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)
+ self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths)
end
end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 37ff10e852..26a85d4de8 100644
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -1,70 +1,70 @@
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
-require 'active_support'
+require 'active_support/ruby/shim'
module ActionController
extend ActiveSupport::Autoload
- deferrable do
- autoload :Base
- autoload :Caching
- autoload :PolymorphicRoutes
- autoload :Translation
- autoload :Metal
- autoload :Middleware
+ autoload :Base
+ autoload :Caching
+ autoload :PolymorphicRoutes
+ autoload :Translation
+ autoload :Metal
+ autoload :Middleware
- autoload_under "metal" do
- autoload :Benchmarking
- autoload :ConditionalGet
- autoload :Configuration
- autoload :Head
- autoload :Helpers
- autoload :HideActions
- autoload :Layouts
- autoload :MimeResponds
- autoload :RackConvenience
- autoload :Compatibility
- autoload :Redirector
- autoload :RenderingController
- autoload :RenderOptions
- autoload :Rescue
- autoload :Responder
- autoload :Session
- autoload :SessionManagement
- autoload :UrlFor
- autoload :Verification
- autoload :Flash
- autoload :RequestForgeryProtection
- autoload :Streaming
- autoload :HttpAuthentication
- autoload :FilterParameterLogging
- autoload :Cookies
- end
-
- autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
- autoload :PerformanceTest, 'action_controller/deprecated/performance_test'
- autoload :Routing, 'action_controller/deprecated'
- autoload :Integration, 'action_controller/deprecated/integration_test'
- autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
+ autoload_under "metal" do
+ autoload :Benchmarking
+ autoload :ConditionalGet
+ autoload :Configuration
+ autoload :Head
+ autoload :Helpers
+ autoload :HideActions
+ autoload :Layouts
+ autoload :Logger
+ autoload :MimeResponds
+ autoload :RackDelegation
+ autoload :Compatibility
+ autoload :Redirecting
+ autoload :Rendering
+ autoload :Renderers
+ autoload :Rescue
+ autoload :Responder
+ autoload :SessionManagement
+ autoload :UrlFor
+ autoload :Verification
+ autoload :Flash
+ autoload :RequestForgeryProtection
+ autoload :Streaming
+ autoload :HttpAuthentication
+ autoload :FilterParameterLogging
+ autoload :Cookies
end
- autoload :RecordIdentifier
- autoload :UrlRewriter
- autoload :UrlWriter, 'action_controller/url_rewriter'
+ autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
+ autoload :PerformanceTest, 'action_controller/deprecated/performance_test'
+ autoload :Routing, 'action_controller/deprecated'
+ autoload :Integration, 'action_controller/deprecated/integration_test'
+ autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
- # TODO: Don't autoload exceptions, setup explicit
- # requires for files that need them
- autoload_at "action_controller/metal/exceptions" do
- autoload :ActionControllerError
- autoload :RenderError
- autoload :RoutingError
- autoload :MethodNotAllowed
- autoload :NotImplemented
- autoload :UnknownController
- autoload :MissingFile
- autoload :RenderError
- autoload :SessionOverflowError
- autoload :UnknownHttpMethod
+ eager_autoload do
+ autoload :RecordIdentifier
+ autoload :UrlRewriter
+ autoload :UrlWriter, 'action_controller/url_rewriter'
+
+ # TODO: Don't autoload exceptions, setup explicit
+ # requires for files that need them
+ autoload_at "action_controller/metal/exceptions" do
+ autoload :ActionControllerError
+ autoload :RenderError
+ autoload :RoutingError
+ autoload :MethodNotAllowed
+ autoload :NotImplemented
+ autoload :UnknownController
+ autoload :MissingFile
+ autoload :RenderError
+ autoload :SessionOverflowError
+ autoload :UnknownHttpMethod
+ end
end
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 48bfbab215..dbba69f637 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -8,12 +8,13 @@ module ActionController
include ActionController::Helpers
include ActionController::HideActions
include ActionController::UrlFor
- include ActionController::Redirector
- include ActionController::RenderingController
- include ActionController::RenderOptions::All
+ include ActionController::Redirecting
+ include ActionController::Rendering
+ include ActionController::Renderers::All
include ActionController::Layouts
include ActionController::ConditionalGet
- include ActionController::RackConvenience
+ include ActionController::RackDelegation
+ include ActionController::Logger
include ActionController::Benchmarking
include ActionController::Configuration
@@ -26,7 +27,6 @@ module ActionController
include ActionController::Compatibility
include ActionController::Cookies
- include ActionController::Session
include ActionController::Flash
include ActionController::Verification
include ActionController::RequestForgeryProtection
@@ -90,7 +90,7 @@ module ActionController
end
if options[:status]
- options[:status] = _interpret_status(options[:status])
+ options[:status] = Rack::Utils.status_code(options[:status])
end
options[:update] = blk if block_given?
@@ -106,71 +106,5 @@ module ActionController
options = _normalize_options(action, options, &blk)
super(options)
end
-
- # 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
-
- private
- def _interpret_status(status)
- if status.is_a?(Symbol)
- (ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[status] || 500)
- else
- status.to_i
- end
- end
end
end
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb
index ad357cceda..d784138ebe 100644
--- a/actionpack/lib/action_controller/caching.rb
+++ b/actionpack/lib/action_controller/caching.rb
@@ -32,11 +32,13 @@ module ActionController #:nodoc:
extend ActiveSupport::Concern
extend ActiveSupport::Autoload
- autoload :Actions
- autoload :Fragments
- autoload :Pages
- autoload :Sweeper, 'action_controller/caching/sweeping'
- autoload :Sweeping, 'action_controller/caching/sweeping'
+ eager_autoload do
+ autoload :Actions
+ autoload :Fragments
+ autoload :Pages
+ autoload :Sweeper, 'action_controller/caching/sweeping'
+ autoload :Sweeping, 'action_controller/caching/sweeping'
+ end
included do
@@cache_store = nil
diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb
index 60b3f9a89b..b436de9878 100644
--- a/actionpack/lib/action_controller/metal.rb
+++ b/actionpack/lib/action_controller/metal.rb
@@ -45,7 +45,7 @@ module ActionController
# The details below can be overridden to support a specific
# Request and Response object. The default ActionController::Base
- # implementation includes RackConvenience, which makes a request
+ # implementation includes RackDelegation, which makes a request
# and response object available. You might wish to control the
# environment and response manually for performance reasons.
@@ -57,7 +57,7 @@ module ActionController
end
# Basic implementations for content_type=, location=, and headers are
- # provided to reduce the dependency on the RackConvenience module
+ # provided to reduce the dependency on the RackDelegation module
# in Renderer and Redirector.
def content_type=(type)
@@ -68,6 +68,10 @@ module ActionController
headers["Location"] = url
end
+ def status=(status)
+ @_status = Rack::Utils.status_code(status)
+ end
+
# :api: private
def dispatch(name, env)
@_env = env
@@ -92,6 +96,7 @@ module ActionController
def initialize(controller, action)
@controller, @action = controller, action
+ @_formats = [Mime::HTML]
end
def call(env)
diff --git a/actionpack/lib/action_controller/metal/benchmarking.rb b/actionpack/lib/action_controller/metal/benchmarking.rb
index e58df69172..f73f635b0d 100644
--- a/actionpack/lib/action_controller/metal/benchmarking.rb
+++ b/actionpack/lib/action_controller/metal/benchmarking.rb
@@ -53,7 +53,6 @@ module ActionController #:nodoc:
log_message << " [#{complete_request_uri rescue "unknown"}]"
logger.info(log_message)
- response.headers["X-Runtime"] = "%.0f" % ms
else
super
end
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index 5156fbc1d5..61e7ece90d 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -2,7 +2,7 @@ module ActionController
module ConditionalGet
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
include Head
# Sets the etag, last_modified, or both on the response and renders a
diff --git a/actionpack/lib/action_controller/metal/cookies.rb b/actionpack/lib/action_controller/metal/cookies.rb
index 6855ca1478..8d5f0d7199 100644
--- a/actionpack/lib/action_controller/metal/cookies.rb
+++ b/actionpack/lib/action_controller/metal/cookies.rb
@@ -46,60 +46,152 @@ module ActionController #:nodoc:
module Cookies
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
included do
helper_method :cookies
+ cattr_accessor :cookie_verifier_secret
end
- protected
- # Returns the cookie container, which operates as described above.
- def cookies
- @cookies ||= CookieJar.build(request, response)
+ protected
+ # Returns the cookie container, which operates as described above.
+ def cookies
+ @cookies ||= CookieJar.build(request, response)
+ end
end
- end
- class CookieJar < Hash #:nodoc:
- def self.build(request, response)
- new.tap do |hash|
- hash.update(request.cookies)
- hash.response = response
+ class CookieJar < Hash #:nodoc:
+ def self.build(request, response)
+ new.tap do |hash|
+ hash.update(request.cookies)
+ hash.response = response
+ end
end
- end
- attr_accessor :response
+ attr_accessor :response
- # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists.
- def [](name)
- super(name.to_s)
- end
+ # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists.
+ def [](name)
+ super(name.to_s)
+ end
+
+ # Sets the cookie named +name+. The second argument may be the very cookie
+ # value, or a hash of options as documented above.
+ def []=(key, options)
+ if options.is_a?(Hash)
+ options.symbolize_keys!
+ value = options[:value]
+ else
+ value = options
+ options = { :value => value }
+ end
- # Sets the cookie named +name+. The second argument may be the very cookie
- # value, or a hash of options as documented above.
- def []=(key, options)
- if options.is_a?(Hash)
+ super(key.to_s, value)
+
+ options[:path] ||= "/"
+ response.set_cookie(key, options)
+ end
+
+ # Removes the cookie on the client machine by setting the value to an empty string
+ # and setting its expiration date into the past. Like <tt>[]=</tt>, you can pass in
+ # an options hash to delete cookies with extra data such as a <tt>:path</tt>.
+ def delete(key, options = {})
options.symbolize_keys!
- value = options[:value]
- else
- value = options
- options = { :value => value }
+ options[:path] ||= "/"
+ value = super(key.to_s)
+ response.delete_cookie(key, options)
+ value
end
- super(key.to_s, value)
-
- options[:path] ||= "/"
- response.set_cookie(key, options)
+ # Returns a jar that'll automatically set the assigned cookies to have an expiration date 20 years from now. Example:
+ #
+ # cookies.permanent[:prefers_open_id] = true
+ # # => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
+ #
+ # This jar is only meant for writing. You'll read permanent cookies through the regular accessor.
+ #
+ # This jar allows chaining with the signed jar as well, so you can set permanent, signed cookies. Examples:
+ #
+ # cookies.permanent.signed[:remember_me] = current_user.id
+ # # => Set-Cookie: discount=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
+ def permanent
+ @permanent ||= PermanentCookieJar.new(self)
+ end
+
+ # Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from
+ # the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed
+ # cookie was tampered with by the user (or a 3rd party), an ActiveSupport::MessageVerifier::InvalidSignature exception will
+ # be raised.
+ #
+ # This jar requires that you set a suitable secret for the verification on ActionController::Base.cookie_verifier_secret.
+ #
+ # Example:
+ #
+ # cookies.signed[:discount] = 45
+ # # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/
+ #
+ # cookies.signed[:discount] # => 45
+ def signed
+ @signed ||= SignedCookieJar.new(self)
+ end
end
-
- # Removes the cookie on the client machine by setting the value to an empty string
- # and setting its expiration date into the past. Like <tt>[]=</tt>, you can pass in
- # an options hash to delete cookies with extra data such as a <tt>:path</tt>.
- def delete(key, options = {})
- options.symbolize_keys!
- options[:path] ||= "/"
- value = super(key.to_s)
- response.delete_cookie(key, options)
- value
+
+ class PermanentCookieJar < CookieJar #:nodoc:
+ def initialize(parent_jar)
+ @parent_jar = parent_jar
+ end
+
+ def []=(key, options)
+ if options.is_a?(Hash)
+ options.symbolize_keys!
+ else
+ options = { :value => options }
+ end
+
+ options[:expires] = 20.years.from_now
+ @parent_jar[key] = options
+ end
+
+ def signed
+ @signed ||= SignedCookieJar.new(self)
+ end
+
+ def controller
+ @parent_jar.controller
+ end
+
+ def method_missing(method, *arguments, &block)
+ @parent_jar.send(method, *arguments, &block)
+ end
end
+
+ class SignedCookieJar < CookieJar #:nodoc:
+ def initialize(parent_jar)
+ unless ActionController::Base.cookie_verifier_secret
+ raise "You must set ActionController::Base.cookie_verifier_secret to use signed cookies"
+ end
+
+ @parent_jar = parent_jar
+ @verifier = ActiveSupport::MessageVerifier.new(ActionController::Base.cookie_verifier_secret)
+ end
+
+ def [](name)
+ @verifier.verify(@parent_jar[name])
+ end
+
+ def []=(key, options)
+ if options.is_a?(Hash)
+ options.symbolize_keys!
+ options[:value] = @verifier.generate(options[:value])
+ else
+ options = { :value => @verifier.generate(options) }
+ end
+
+ @parent_jar[key] = options
+ end
+
+ def method_missing(method, *arguments, &block)
+ @parent_jar.send(method, *arguments, &block)
+ end
end
end
diff --git a/actionpack/lib/action_controller/metal/flash.rb b/actionpack/lib/action_controller/metal/flash.rb
index 9d08ed6081..581ff6109e 100644
--- a/actionpack/lib/action_controller/metal/flash.rb
+++ b/actionpack/lib/action_controller/metal/flash.rb
@@ -28,7 +28,9 @@ module ActionController #:nodoc:
module Flash
extend ActiveSupport::Concern
- include Session
+ included do
+ helper_method :alert, :notice
+ end
class FlashNow #:nodoc:
def initialize(flash)
@@ -147,6 +149,27 @@ module ActionController #:nodoc:
@_flash
end
+ # Convenience accessor for flash[:alert]
+ def alert
+ flash[:alert]
+ end
+
+ # Convenience accessor for flash[:alert]=
+ def alert=(message)
+ flash[:alert] = message
+ end
+
+ # Convenience accessor for flash[:notice]
+ def notice
+ flash[:notice]
+ end
+
+ # Convenience accessor for flash[:notice]=
+ def notice=(message)
+ flash[:notice] = message
+ end
+
+
protected
def process_action(method_name)
@_flash = nil
@@ -159,5 +182,21 @@ module ActionController #:nodoc:
super
@_flash = nil
end
+
+ def redirect_to(options = {}, response_status_and_flash = {}) #:doc:
+ if alert = response_status_and_flash.delete(:alert)
+ flash[:alert] = alert
+ end
+
+ if notice = response_status_and_flash.delete(:notice)
+ flash[:notice] = notice
+ end
+
+ if other_flashes = response_status_and_flash.delete(:flash)
+ flash.update(other_flashes)
+ end
+
+ super(options, response_status_and_flash)
+ end
end
end
diff --git a/actionpack/lib/action_controller/metal/head.rb b/actionpack/lib/action_controller/metal/head.rb
index 68fa0a0402..c82d9cf369 100644
--- a/actionpack/lib/action_controller/metal/head.rb
+++ b/actionpack/lib/action_controller/metal/head.rb
@@ -1,5 +1,7 @@
module ActionController
module Head
+ include UrlFor
+
# Return a response that has no content (merely headers). The options
# argument is interpreted to be a hash of header names and values.
# This allows you to easily return a response that consists only of
@@ -21,7 +23,10 @@ module ActionController
headers[key.to_s.dasherize.split(/-/).map { |v| v.capitalize }.join("-")] = value.to_s
end
- render :nothing => true, :status => status, :location => location
+ self.status = status
+ self.location = url_for(location) if location
+ self.content_type = Mime[formats.first]
+ self.response_body = " "
end
end
end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/metal/layouts.rb b/actionpack/lib/action_controller/metal/layouts.rb
index cc7088248a..f44498a884 100644
--- a/actionpack/lib/action_controller/metal/layouts.rb
+++ b/actionpack/lib/action_controller/metal/layouts.rb
@@ -158,7 +158,7 @@ module ActionController
module Layouts
extend ActiveSupport::Concern
- include ActionController::RenderingController
+ include ActionController::Rendering
include AbstractController::Layouts
module ClassMethods
diff --git a/actionpack/lib/action_controller/metal/logger.rb b/actionpack/lib/action_controller/metal/logger.rb
new file mode 100644
index 0000000000..956d7dd371
--- /dev/null
+++ b/actionpack/lib/action_controller/metal/logger.rb
@@ -0,0 +1,34 @@
+require 'abstract_controller/logger'
+
+module ActionController
+ module Logger
+ # Override process_action in the AbstractController::Base
+ # to log details about the method.
+ def process_action(action)
+ result = ActiveSupport::Notifications.instrument(:process_action,
+ :controller => self, :action => action) do
+ super
+ end
+
+ if logger
+ log = AbstractController::Logger::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
+
+ result
+ end
+
+ private
+
+ # Returns the request origin with the IP and time. This needs to be cached,
+ # otherwise we would get different results for each time it calls.
+ def request_origin
+ @request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}"
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/metal/rack_convenience.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb
index 131d20114d..bb55383631 100644
--- a/actionpack/lib/action_controller/metal/rack_convenience.rb
+++ b/actionpack/lib/action_controller/metal/rack_delegation.rb
@@ -1,8 +1,12 @@
+require 'action_dispatch/http/request'
+require 'action_dispatch/http/response'
+
module ActionController
- module RackConvenience
+ module RackDelegation
extend ActiveSupport::Concern
included do
+ delegate :session, :to => "@_request"
delegate :headers, :status=, :location=, :content_type=,
:status, :location, :content_type, :to => "@_response"
attr_internal :request
@@ -23,5 +27,9 @@ module ActionController
response.body = body if response
super
end
+
+ def reset_session
+ @_request.reset_session
+ end
end
end
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
new file mode 100644
index 0000000000..7a2f9a6fc5
--- /dev/null
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -0,0 +1,90 @@
+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 Redirecting
+ extend ActiveSupport::Concern
+ include AbstractController::Logger
+
+ # 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
+ #
+ # It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names
+ # +alert+ and +notice+ as well as a general purpose +flash+ bucket.
+ #
+ # Examples:
+ # redirect_to post_url(@post), :alert => "Watch it, mister!"
+ # redirect_to post_url(@post), :status=> :found, :notice => "Pay attention to the road"
+ # redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id }
+ # redirect_to { :action=>'atom' }, :alert => "Something serious happened"
+ #
+ # 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?
+ raise AbstractController::DoubleRenderError if response_body
+
+ self.status = _extract_redirect_to_status(options, response_status)
+ self.location = _compute_redirect_to_location(options)
+ self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(location)}\">redirected</a>.</body></html>"
+
+ logger.info("Redirected to #{location}") if logger && logger.info?
+ end
+
+ private
+ def _extract_redirect_to_status(options, response_status)
+ status = if options.is_a?(Hash) && options.key?(:status)
+ Rack::Utils.status_code(options.delete(:status))
+ elsif response_status.key?(:status)
+ Rack::Utils.status_code(response_status[:status])
+ else
+ 302
+ end
+ end
+
+ def _compute_redirect_to_location(options)
+ 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.gsub(/[\r\n]/, '')
+ end
+ end
+end
diff --git a/actionpack/lib/action_controller/metal/redirector.rb b/actionpack/lib/action_controller/metal/redirector.rb
deleted file mode 100644
index b55f5e7bfc..0000000000
--- a/actionpack/lib/action_controller/metal/redirector.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-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
- extend ActiveSupport::Concern
- include AbstractController::Logger
-
- def redirect_to(url, status) #:doc:
- raise AbstractController::DoubleRenderError if response_body
- logger.info("Redirected to #{url}") if logger && logger.info?
- self.status = status
- self.location = url.gsub(/[\r\n]/, '')
- self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(url)}\">redirected</a>.</body></html>"
- end
- end
-end
diff --git a/actionpack/lib/action_controller/metal/render_options.rb b/actionpack/lib/action_controller/metal/renderers.rb
index b6a7ca0eda..c1ba47927a 100644
--- a/actionpack/lib/action_controller/metal/render_options.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -1,10 +1,9 @@
module ActionController
-
def self.add_renderer(key, &block)
- RenderOptions.add(key, &block)
+ Renderers.add(key, &block)
end
- module RenderOptions
+ module Renderers
extend ActiveSupport::Concern
included do
@@ -52,7 +51,7 @@ module ActionController
module All
extend ActiveSupport::Concern
- include RenderOptions
+ include Renderers
INCLUDED = []
included do
diff --git a/actionpack/lib/action_controller/metal/rendering_controller.rb b/actionpack/lib/action_controller/metal/rendering.rb
index 237299cd30..20eb524e50 100644
--- a/actionpack/lib/action_controller/metal/rendering_controller.rb
+++ b/actionpack/lib/action_controller/metal/rendering.rb
@@ -1,9 +1,9 @@
module ActionController
- module RenderingController
+ module Rendering
extend ActiveSupport::Concern
included do
- include AbstractController::RenderingController
+ include AbstractController::Rendering
include AbstractController::LocalizedCache
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 173df79ee7..2826b1e34c 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -5,7 +5,7 @@ module ActionController #:nodoc:
module RequestForgeryProtection
extend ActiveSupport::Concern
- include AbstractController::Helpers, Session
+ include AbstractController::Helpers
included do
# Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
@@ -19,31 +19,31 @@ module ActionController #:nodoc:
helper_method :form_authenticity_token
helper_method :protect_against_forgery?
end
-
- # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
- # web application, not a forged link from another site, is done by embedding a token based on a random
+
+ # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current
+ # web application, not a forged link from another site, is done by embedding a token based on a random
# string stored in the session (which an attacker wouldn't know) in all forms and Ajax requests generated
- # by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
- # requests are checked, so this will not protect your XML API (presumably you'll have a different
- # authentication scheme there anyway). Also, GET requests are not protected as these should be
+ # by Rails and then verifying the authenticity of that token in the controller. Only HTML/JavaScript
+ # requests are checked, so this will not protect your XML API (presumably you'll have a different
+ # authentication scheme there anyway). Also, GET requests are not protected as these should be
# idempotent anyway.
#
# This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
- # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
+ # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the
# error message in production by editing public/422.html. A call to this method in ApplicationController is
# generated by default in post-Rails 2.0 applications.
#
- # The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
- # manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
- # include a hidden field named like that and set its value to what is returned by
+ # The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form
+ # manually (without the use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to
+ # include a hidden field named like that and set its value to what is returned by
# <tt>form_authenticity_token</tt>.
#
- # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
+ # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails
# 1.x, add this to config/environments/test.rb:
#
# # Disable request forgery protection in test environment
# config.action_controller.allow_forgery_protection = false
- #
+ #
# == Learn more about CSRF (Cross-Site Request Forgery) attacks
#
# Here are some resources:
@@ -52,11 +52,11 @@ module ActionController #:nodoc:
#
# Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
# There are a few guidelines you should follow:
- #
+ #
# * Keep your GET requests safe and idempotent. More reading material:
# * http://www.xml.com/pub/a/2002/04/24/deviant.html
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
- # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
+ # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look
# for "Expires: at end of session"
#
module ClassMethods
@@ -92,7 +92,7 @@ module ActionController #:nodoc:
# * is it a GET request? Gets should be safe and idempotent
# * Does the form_authenticity_token match the given token value from the params?
def verified_request?
- !protect_against_forgery? || request.forgery_whitelisted? ||
+ !protect_against_forgery? || request.forgery_whitelisted? ||
form_authenticity_token == params[request_forgery_protection_token]
end
diff --git a/actionpack/lib/action_controller/metal/session.rb b/actionpack/lib/action_controller/metal/session.rb
deleted file mode 100644
index bcedd6e1c7..0000000000
--- a/actionpack/lib/action_controller/metal/session.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-module ActionController
- module Session
- extend ActiveSupport::Concern
-
- include RackConvenience
-
- def session
- @_request.session
- end
-
- def reset_session
- @_request.reset_session
- end
- end
-end
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 43c661bef4..288b5d7c99 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -4,7 +4,7 @@ module ActionController #:nodoc:
module Streaming
extend ActiveSupport::Concern
- include ActionController::RenderingController
+ include ActionController::Rendering
DEFAULT_SEND_FILE_OPTIONS = {
:type => 'application/octet-stream'.freeze,
diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb
index a4a1116d9e..c193a5eff4 100644
--- a/actionpack/lib/action_controller/metal/testing.rb
+++ b/actionpack/lib/action_controller/metal/testing.rb
@@ -2,7 +2,7 @@ module ActionController
module Testing
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
# OMG MEGA HAX
def process_with_new_base_test(request, response)
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 14c6523045..8c3810ebcb 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -2,7 +2,7 @@ module ActionController
module UrlFor
extend ActiveSupport::Concern
- include RackConvenience
+ include RackDelegation
# Overwrite to implement a number of default options that all url_for-based methods will use. The default options should come in
# the form of a hash, just like the one you would use for url_for directly. Example:
diff --git a/actionpack/lib/action_controller/metal/verification.rb b/actionpack/lib/action_controller/metal/verification.rb
index 500cced539..bce942b588 100644
--- a/actionpack/lib/action_controller/metal/verification.rb
+++ b/actionpack/lib/action_controller/metal/verification.rb
@@ -2,7 +2,7 @@ module ActionController #:nodoc:
module Verification #:nodoc:
extend ActiveSupport::Concern
- include AbstractController::Callbacks, Session, Flash, RenderingController
+ include AbstractController::Callbacks, Flash, Rendering
# This module provides a class-level method for specifying that certain
# actions are guarded against being called without certain prerequisites
@@ -35,7 +35,7 @@ module ActionController #:nodoc:
# :add_flash => { "alert" => "Failed to create your message" },
# :redirect_to => :category_url
#
- # Note that these prerequisites are not business rules. They do not examine
+ # Note that these prerequisites are not business rules. They do not examine
# the content of the session or the parameters. That level of validation should
# be encapsulated by your domain model or helper methods in the controller.
module ClassMethods
@@ -43,40 +43,40 @@ module ActionController #:nodoc:
# the user is redirected to a different action. The +options+ parameter
# is a hash consisting of the following key/value pairs:
#
- # <tt>:params</tt>::
- # a single key or an array of keys that must be in the <tt>params</tt>
+ # <tt>:params</tt>::
+ # a single key or an array of keys that must be in the <tt>params</tt>
# hash in order for the action(s) to be safely called.
- # <tt>:session</tt>::
- # a single key or an array of keys that must be in the <tt>session</tt>
+ # <tt>:session</tt>::
+ # a single key or an array of keys that must be in the <tt>session</tt>
# in order for the action(s) to be safely called.
- # <tt>:flash</tt>::
- # a single key or an array of keys that must be in the flash in order
+ # <tt>:flash</tt>::
+ # a single key or an array of keys that must be in the flash in order
# for the action(s) to be safely called.
- # <tt>:method</tt>::
- # a single key or an array of keys--any one of which must match the
- # current request method in order for the action(s) to be safely called.
- # (The key should be a symbol: <tt>:get</tt> or <tt>:post</tt>, for
+ # <tt>:method</tt>::
+ # a single key or an array of keys--any one of which must match the
+ # current request method in order for the action(s) to be safely called.
+ # (The key should be a symbol: <tt>:get</tt> or <tt>:post</tt>, for
# example.)
- # <tt>:xhr</tt>::
- # true/false option to ensure that the request is coming from an Ajax
- # call or not.
- # <tt>:add_flash</tt>::
- # a hash of name/value pairs that should be merged into the session's
+ # <tt>:xhr</tt>::
+ # true/false option to ensure that the request is coming from an Ajax
+ # call or not.
+ # <tt>:add_flash</tt>::
+ # a hash of name/value pairs that should be merged into the session's
# flash if the prerequisites cannot be satisfied.
- # <tt>:add_headers</tt>::
- # a hash of name/value pairs that should be merged into the response's
+ # <tt>:add_headers</tt>::
+ # a hash of name/value pairs that should be merged into the response's
# headers hash if the prerequisites cannot be satisfied.
- # <tt>:redirect_to</tt>::
- # the redirection parameters to be used when redirecting if the
- # prerequisites cannot be satisfied. You can redirect either to named
+ # <tt>:redirect_to</tt>::
+ # the redirection parameters to be used when redirecting if the
+ # prerequisites cannot be satisfied. You can redirect either to named
# route or to the action in some controller.
- # <tt>:render</tt>::
+ # <tt>:render</tt>::
# the render parameters to be used when the prerequisites cannot be satisfied.
- # <tt>:only</tt>::
- # only apply this verification to the actions specified in the associated
+ # <tt>:only</tt>::
+ # only apply this verification to the actions specified in the associated
# array (may also be a single value).
- # <tt>:except</tt>::
- # do not apply this verification to the actions specified in the associated
+ # <tt>:except</tt>::
+ # do not apply this verification to the actions specified in the associated
# array (may also be a single value).
def verify(options={})
before_filter :only => options[:only], :except => options[:except] do
@@ -94,31 +94,31 @@ module ActionController #:nodoc:
apply_remaining_actions(options) unless performed?
end
end
-
+
def prereqs_invalid?(options) # :nodoc:
- verify_presence_of_keys_in_hash_flash_or_params(options) ||
- verify_method(options) ||
+ verify_presence_of_keys_in_hash_flash_or_params(options) ||
+ verify_method(options) ||
verify_request_xhr_status(options)
end
-
+
def verify_presence_of_keys_in_hash_flash_or_params(options) # :nodoc:
[*options[:params] ].find { |v| v && params[v.to_sym].nil? } ||
[*options[:session]].find { |v| session[v].nil? } ||
[*options[:flash] ].find { |v| flash[v].nil? }
end
-
+
def verify_method(options) # :nodoc:
[*options[:method]].all? { |v| request.method != v.to_sym } if options[:method]
end
-
+
def verify_request_xhr_status(options) # :nodoc:
request.xhr? != options[:xhr] unless options[:xhr].nil?
end
-
+
def apply_redirect_to(redirect_to_option) # :nodoc:
(redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.__send__(redirect_to_option) : redirect_to_option
end
-
+
def apply_remaining_actions(options) # :nodoc:
case
when options[:render] ; render(options[:render])
diff --git a/actionpack/lib/action_controller/notifications.rb b/actionpack/lib/action_controller/notifications.rb
deleted file mode 100644
index 1a4f29e0e2..0000000000
--- a/actionpack/lib/action_controller/notifications.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require 'active_support/notifications'
-
-ActiveSupport::Notifications.subscribe(/(read|write|cache|expire|exist)_(fragment|page)\??/) do |*args|
- event = ActiveSupport::Notifications::Event.new(*args)
-
- if logger = ActionController::Base.logger
- human_name = event.name.to_s.humanize
- logger.info("#{human_name} (%.1fms)" % event.duration)
- end
-end
diff --git a/actionpack/lib/action_controller/rails.rb b/actionpack/lib/action_controller/rails.rb
new file mode 100644
index 0000000000..36a52b3149
--- /dev/null
+++ b/actionpack/lib/action_controller/rails.rb
@@ -0,0 +1,102 @@
+module ActionController
+ class Plugin < Rails::Plugin
+ plugin_name :action_controller
+
+ initializer "action_controller.set_configs" do |app|
+ app.config.action_controller.each do |k,v|
+ ActionController::Base.send "#{k}=", v
+ end
+ end
+
+ # TODO: ActionController::Base.logger should delegate to its own config.logger
+ initializer "action_controller.logger" do
+ ActionController::Base.logger ||= Rails.logger
+ end
+
+ # Routing must be initialized after plugins to allow the former to extend the routes
+ # ---
+ # If Action Controller is not one of the loaded frameworks (Configuration#frameworks)
+ # this does nothing. Otherwise, it loads the routing definitions and sets up
+ # loading module used to lazily load controllers (Configuration#controller_paths).
+ initializer "action_controller.initialize_routing" do |app|
+ app.route_configuration_files << app.config.routes_configuration_file
+ app.route_configuration_files << app.config.builtin_routes_configuration_file
+ app.reload_routes!
+ end
+
+ # Include middleware to serve up static assets
+ initializer "action_controller.initialize_static_server" do |app|
+ if app.config.serve_static_assets
+ app.config.middleware.use(ActionDispatch::Static, Rails.public_path)
+ end
+ end
+
+ initializer "action_controller.initialize_middleware_stack" do |app|
+ middleware = app.config.middleware
+ middleware.use(::Rack::Lock, :if => lambda { ActionController::Base.allow_concurrency })
+ middleware.use(::Rack::Runtime)
+ middleware.use(ActionDispatch::ShowExceptions, lambda { ActionController::Base.consider_all_requests_local })
+ middleware.use(ActionDispatch::Callbacks, lambda { ActionController::Dispatcher.prepare_each_request })
+ middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options })
+ middleware.use(ActionDispatch::ParamsParser)
+ middleware.use(::Rack::MethodOverride)
+ middleware.use(::Rack::Head)
+ middleware.use(ActionDispatch::StringCoercion)
+ end
+
+ initializer "action_controller.initialize_framework_caches" do
+ ActionController::Base.cache_store ||= RAILS_CACHE
+ end
+
+ # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+
+ # (but only for those frameworks that are to be loaded). If the framework's
+ # paths have already been set, it is not changed, otherwise it is
+ # set to use Configuration#view_path.
+ initializer "action_controller.initialize_framework_views" do |app|
+ # TODO: this should be combined with the logic for default config.action_controller.view_paths
+ view_path = ActionView::PathSet.type_cast(app.config.view_path, app.config.cache_classes)
+ ActionController::Base.view_paths = view_path if ActionController::Base.view_paths.blank?
+ end
+
+ initializer "action_controller.initialize_metal" do |app|
+ Rails::Rack::Metal.requested_metals = app.config.metals
+
+ app.config.middleware.insert_before(:"ActionDispatch::ParamsParser",
+ Rails::Rack::Metal, :if => Rails::Rack::Metal.metals.any?)
+ end
+
+ # # Prepare dispatcher callbacks and run 'prepare' callbacks
+ initializer "action_controller.prepare_dispatcher" do |app|
+ # TODO: This used to say unless defined?(Dispatcher). Find out why and fix.
+ require 'rails/dispatcher'
+
+ Dispatcher.define_dispatcher_callbacks(app.config.cache_classes)
+
+ unless app.config.cache_classes
+ # Setup dev mode route reloading
+ routes_last_modified = app.routes_changed_at
+ reload_routes = lambda do
+ unless app.routes_changed_at == routes_last_modified
+ routes_last_modified = app.routes_changed_at
+ app.reload_routes!
+ end
+ end
+ ActionDispatch::Callbacks.before_dispatch { |callbacks| reload_routes.call }
+ end
+ end
+
+ initializer "action_controller.notifications" do |app|
+ require 'active_support/notifications'
+
+ ActiveSupport::Notifications.subscribe(/(read|write|cache|expire|exist)_(fragment|page)\??/) do |*args|
+ event = ActiveSupport::Notifications::Event.new(*args)
+
+ if logger = ActionController::Base.logger
+ human_name = event.name.to_s.humanize
+ logger.info("#{human_name} (%.1fms)" % event.duration)
+ end
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/vendor/html-scanner.rb b/actionpack/lib/action_controller/vendor/html-scanner.rb
index 2cb20ddd05..879b31e60e 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner.rb
@@ -3,16 +3,18 @@ $LOAD_PATH << "#{File.dirname(__FILE__)}/html-scanner"
module HTML
extend ActiveSupport::Autoload
- autoload :CDATA, 'html/node'
- autoload :Document, 'html/document'
- autoload :FullSanitizer, 'html/sanitizer'
- autoload :LinkSanitizer, 'html/sanitizer'
- autoload :Node, 'html/node'
- autoload :Sanitizer, 'html/sanitizer'
- autoload :Selector, 'html/selector'
- autoload :Tag, 'html/node'
- autoload :Text, 'html/node'
- autoload :Tokenizer, 'html/tokenizer'
- autoload :Version, 'html/version'
- autoload :WhiteListSanitizer, 'html/sanitizer'
+ eager_autoload do
+ autoload :CDATA, 'html/node'
+ autoload :Document, 'html/document'
+ autoload :FullSanitizer, 'html/sanitizer'
+ autoload :LinkSanitizer, 'html/sanitizer'
+ autoload :Node, 'html/node'
+ autoload :Sanitizer, 'html/sanitizer'
+ autoload :Selector, 'html/selector'
+ autoload :Tag, 'html/node'
+ autoload :Text, 'html/node'
+ autoload :Tokenizer, 'html/tokenizer'
+ autoload :Version, 'html/version'
+ autoload :WhiteListSanitizer, 'html/sanitizer'
+ end
end
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index feed6a8e25..0696cb017c 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -23,7 +23,7 @@
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
-require 'active_support'
+require 'active_support/ruby/shim'
require 'rack'
@@ -37,44 +37,39 @@ module ActionDispatch
autoload_under 'http' do
autoload :Request
autoload :Response
- autoload :StatusCodes
- autoload :Utils
end
- deferrable do
- autoload_under 'middleware' do
- autoload :Callbacks
- autoload :ParamsParser
- autoload :Rescue
- autoload :ShowExceptions
- autoload :Static
- autoload :StringCoercion
- end
-
- autoload :MiddlewareStack, 'action_dispatch/middleware/stack'
- autoload :Routing
+ autoload_under 'middleware' do
+ autoload :Callbacks
+ autoload :Cascade
+ autoload :ParamsParser
+ autoload :Rescue
+ autoload :ShowExceptions
+ autoload :Static
+ autoload :StringCoercion
+ end
- module Http
- autoload :Headers, 'action_dispatch/http/headers'
- end
+ autoload :MiddlewareStack, 'action_dispatch/middleware/stack'
+ autoload :Routing
- module Session
- autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
- autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
- autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
- end
+ module Http
+ autoload :Headers, 'action_dispatch/http/headers'
+ end
- autoload_under 'testing' do
- autoload :Assertions
- autoload :Integration
- autoload :PerformanceTest
- autoload :TestProcess
- autoload :TestRequest
- autoload :TestResponse
- end
+ module Session
+ autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
+ autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
+ autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
end
- autoload :HTML, 'action_controller/vendor/html-scanner'
+ autoload_under 'testing' do
+ autoload :Assertions
+ autoload :Integration
+ autoload :PerformanceTest
+ autoload :TestProcess
+ autoload :TestRequest
+ autoload :TestResponse
+ end
end
autoload :Mime, 'action_dispatch/http/mime_type'
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 7d1f5a4504..6e8a5dcb8a 100755
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -18,7 +18,7 @@ module ActionDispatch
HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
- HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
+ HTTP_NEGOTIATE HTTP_PRAGMA ].each do |env|
define_method(env.sub(/^HTTP_/n, '').downcase) do
@env[env]
end
@@ -465,6 +465,15 @@ EOM
session['flash'] || {}
end
+ # Returns the authorization header regardless of whether it was specified directly or through one of the
+ # proxy alternatives.
+ def authorization
+ @env['HTTP_AUTHORIZATION'] ||
+ @env['X-HTTP_AUTHORIZATION'] ||
+ @env['X_HTTP_AUTHORIZATION'] ||
+ @env['REDIRECT_X_HTTP_AUTHORIZATION']
+ end
+
# Receives an array of mimes and return the first user sent mime that
# matches the order array.
#
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 378fd5e61d..8524bbd993 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -60,7 +60,7 @@ module ActionDispatch # :nodoc:
end
def status=(status)
- @status = status.to_i
+ @status = Rack::Utils.status_code(status)
end
# The response code of the request
@@ -74,7 +74,7 @@ module ActionDispatch # :nodoc:
end
def message
- StatusCodes::STATUS_CODES[@status]
+ Rack::Utils::HTTP_STATUS_CODES[@status]
end
alias_method :status_message, :message
@@ -145,18 +145,6 @@ module ActionDispatch # :nodoc:
cattr_accessor(:default_charset) { "utf-8" }
- def assign_default_content_type_and_charset!
- return if headers[CONTENT_TYPE].present?
-
- @content_type ||= Mime::HTML
- @charset ||= self.class.default_charset
-
- type = @content_type.to_s.dup
- type << "; charset=#{@charset}" unless @sending_file
-
- headers[CONTENT_TYPE] = type
- end
-
def to_a
assign_default_content_type_and_charset!
handle_conditional_get!
@@ -259,6 +247,18 @@ module ActionDispatch # :nodoc:
!@blank && @body.respond_to?(:all?) && @body.all? { |part| part.is_a?(String) }
end
+ def assign_default_content_type_and_charset!
+ return if headers[CONTENT_TYPE].present?
+
+ @content_type ||= Mime::HTML
+ @charset ||= self.class.default_charset
+
+ type = @content_type.to_s.dup
+ type << "; charset=#{@charset}" unless @sending_file
+
+ headers[CONTENT_TYPE] = type
+ end
+
DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
def set_conditional_cache_control!
@@ -280,7 +280,6 @@ module ActionDispatch # :nodoc:
headers["Cache-Control"] = options.join(", ")
end
-
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/status_codes.rb b/actionpack/lib/action_dispatch/http/status_codes.rb
deleted file mode 100644
index ea1475e827..0000000000
--- a/actionpack/lib/action_dispatch/http/status_codes.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'active_support/inflector'
-
-module ActionDispatch
- module StatusCodes #:nodoc:
- STATUS_CODES = Rack::Utils::HTTP_STATUS_CODES.merge({
- 102 => "Processing",
- 207 => "Multi-Status",
- 226 => "IM Used",
- 422 => "Unprocessable Entity",
- 423 => "Locked",
- 424 => "Failed Dependency",
- 426 => "Upgrade Required",
- 507 => "Insufficient Storage",
- 510 => "Not Extended"
- }).freeze
-
- # Provides a symbol-to-fixnum lookup for converting a symbol (like
- # :created or :not_implemented) into its corresponding HTTP status
- # code (like 200 or 501).
- SYMBOL_TO_STATUS_CODE = STATUS_CODES.inject({}) { |hash, (code, message)|
- hash[ActiveSupport::Inflector.underscore(message.gsub(/ /, "")).to_sym] = code
- hash
- }.freeze
- end
-end
diff --git a/actionpack/lib/action_dispatch/http/utils.rb b/actionpack/lib/action_dispatch/http/utils.rb
deleted file mode 100644
index e04a39935e..0000000000
--- a/actionpack/lib/action_dispatch/http/utils.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-module ActionDispatch
- module Utils
- # TODO: Pull this into rack core
- # http://github.com/halorgium/rack/commit/feaf071c1de743fbd10bc316830180a9af607278
- def parse_config(config)
- if config =~ /\.ru$/
- cfgfile = ::File.read(config)
- if cfgfile[/^#\\(.*)/]
- opts.parse! $1.split(/\s+/)
- end
- inner_app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
- nil, config
- else
- require config
- inner_app = Object.const_get(::File.basename(config, '.rb').capitalize)
- end
- end
- module_function :parse_config
- end
-end
diff --git a/actionpack/lib/action_dispatch/middleware/cascade.rb b/actionpack/lib/action_dispatch/middleware/cascade.rb
new file mode 100644
index 0000000000..9f5c9891f0
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/cascade.rb
@@ -0,0 +1,29 @@
+module ActionDispatch
+ class Cascade
+ def self.new(*apps)
+ apps = apps.flatten
+
+ case apps.length
+ when 0
+ raise ArgumentError, "app is required"
+ when 1
+ apps.first
+ else
+ super(apps)
+ end
+ end
+
+ def initialize(apps)
+ @apps = apps
+ end
+
+ def call(env)
+ result = nil
+ @apps.each do |app|
+ result = app.call(env)
+ break unless result[1]["X-Cascade"] == "pass"
+ end
+ result
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index 32ccb5c931..534390d4aa 100644
--- a/actionpack/lib/action_dispatch/middleware/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -1,4 +1,5 @@
require 'active_support/json'
+require 'action_dispatch/http/request'
module ActionDispatch
class ParamsParser
@@ -31,41 +32,39 @@ module ActionDispatch
return false unless strategy
case strategy
- when Proc
- strategy.call(request.raw_post)
- when :xml_simple, :xml_node
- request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
- when :yaml
- YAML.load(request.body)
- when :json
- if request.body.size == 0
- {}
- else
- data = ActiveSupport::JSON.decode(request.body)
- data = {:_json => data} unless data.is_a?(Hash)
- data.with_indifferent_access
- end
+ when Proc
+ strategy.call(request.raw_post)
+ when :xml_simple, :xml_node
+ request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
+ when :yaml
+ YAML.load(request.body)
+ when :json
+ if request.body.size == 0
+ {}
else
- false
+ data = ActiveSupport::JSON.decode(request.body)
+ data = {:_json => data} unless data.is_a?(Hash)
+ data.with_indifferent_access
+ end
+ else
+ false
end
rescue Exception => e # YAML, XML or Ruby code block errors
logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
raise
- { "body" => request.raw_post,
- "content_type" => request.content_type,
+ { "body" => request.raw_post,
+ "content_type" => request.content_type,
"content_length" => request.content_length,
- "exception" => "#{e.message} (#{e.class})",
- "backtrace" => e.backtrace }
+ "exception" => "#{e.message} (#{e.class})",
+ "backtrace" => e.backtrace }
end
def content_type_from_legacy_post_data_format_header(env)
if x_post_format = env['HTTP_X_POST_DATA_FORMAT']
case x_post_format.to_s.downcase
- when 'yaml'
- return Mime::YAML
- when 'xml'
- return Mime::XML
+ when 'yaml' then return Mime::YAML
+ when 'xml' then return Mime::XML
end
end
@@ -76,4 +75,4 @@ module ActionDispatch
defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index c5c06f74a2..7d4f0998ce 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -1,4 +1,5 @@
require 'rack/utils'
+require 'rack/request'
module ActionDispatch
module Session
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index bd552b458a..f27f22c7e7 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -1,4 +1,5 @@
-require "active_support/core_ext/hash/keys"
+require 'active_support/core_ext/hash/keys'
+require 'rack/request'
module ActionDispatch
module Session
@@ -49,7 +50,7 @@ module ActionDispatch
:expire_after => nil,
:httponly => true
}.freeze
-
+
class OptionsHash < Hash
def initialize(by, env, default_options)
@session_data = env[CookieStore::ENV_SESSION_KEY]
@@ -60,7 +61,7 @@ module ActionDispatch
key == :id ? @session_data[:session_id] : super(key)
end
end
-
+
ENV_SESSION_KEY = "rack.session".freeze
ENV_SESSION_OPTIONS_KEY = "rack.session.options".freeze
HTTP_SET_COOKIE = "Set-Cookie".freeze
@@ -102,7 +103,7 @@ module ActionDispatch
def call(env)
env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
-
+
status, headers, body = @app.call(env)
session_data = env[ENV_SESSION_KEY]
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
index bd87764f5b..4ebc8a2ab9 100644
--- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
@@ -1,4 +1,5 @@
-require "active_support/core_ext/exception"
+require 'active_support/core_ext/exception'
+require 'action_dispatch/http/request'
module ActionDispatch
class ShowExceptions
@@ -101,7 +102,7 @@ module ActionDispatch
end
def status_code(exception)
- ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[@@rescue_responses[exception.class.name]]
+ Rack::Utils.status_code(@@rescue_responses[exception.class.name])
end
def render(status, body)
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index d480af876d..e655d6a708 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -19,9 +19,9 @@ module ActionDispatch
@constraints.each { |constraint|
if constraint.respond_to?(:matches?) && !constraint.matches?(req)
- return [417, {}, []]
+ return [ 404, {'X-Cascade' => 'pass'}, [] ]
elsif constraint.respond_to?(:call) && !constraint.call(req)
- return [417, {}, []]
+ return [ 404, {'X-Cascade' => 'pass'}, [] ]
end
}
@@ -29,90 +29,138 @@ module ActionDispatch
end
end
- module Base
- def initialize(set)
- @set = set
+ class Mapping
+ def initialize(set, scope, args)
+ @set, @scope = set, scope
+ @path, @options = extract_path_and_options(args)
end
- def root(options = {})
- match '/', options.merge(:as => :root)
+ def to_route
+ [ app, conditions, requirements, defaults, @options[:as] ]
end
- def match(*args)
- options = args.extract_options!
+ private
+ def extract_path_and_options(args)
+ options = args.extract_options!
- path = args.first
+ if args.empty?
+ path, to = options.find { |name, value| name.is_a?(String) }
+ options.merge!(:to => to).delete(path) if path
+ else
+ path = args.first
+ end
- conditions, defaults = {}, {}
+ [ normalize_path(path), options ]
+ end
- path = nil if path == ""
- path = "#{@scope[:path]}#{path}" if @scope[:path]
- path = Rack::Mount::Utils.normalize_path(path) if path
+ def normalize_path(path)
+ path = nil if path == ""
+ path = "#{@scope[:path]}#{path}" if @scope[:path]
+ path = Rack::Mount::Utils.normalize_path(path) if path
- raise ArgumentError, "path is required" unless path
+ raise ArgumentError, "path is required" unless path
- constraints = options[:constraints] || {}
- unless constraints.is_a?(Hash)
- block, constraints = constraints, {}
+ path
end
- blocks = ((@scope[:blocks] || []) + [block]).compact
- constraints = (@scope[:constraints] || {}).merge(constraints)
- options.each { |k, v| constraints[k] = v if v.is_a?(Regexp) }
- conditions[:path_info] = path
- requirements = constraints.dup
- path_regexp = Rack::Mount::Strexp.compile(path, constraints, SEPARATORS)
- segment_keys = Rack::Mount::RegexpWithNamedGroups.new(path_regexp).names
- constraints.reject! { |k, v| segment_keys.include?(k.to_s) }
- conditions.merge!(constraints)
+ def app
+ Constraints.new(
+ to.respond_to?(:call) ? to : Routing::RouteSet::Dispatcher.new(:defaults => defaults),
+ blocks
+ )
+ end
- requirements[:controller] ||= @set.controller_constraints
+ def conditions
+ { :path_info => @path }.merge(constraints).merge(request_method_condition)
+ end
- if via = options[:via]
- via = Array(via).map { |m| m.to_s.upcase }
- conditions[:request_method] = Regexp.union(*via)
+ def requirements
+ @requirements ||= returning(@options[:constraints] || {}) do |requirements|
+ requirements.reverse_merge!(@scope[:constraints]) if @scope[:constraints]
+ @options.each { |k, v| requirements[k] = v if v.is_a?(Regexp) }
+ requirements[:controller] ||= @set.controller_constraints
+ end
end
- defaults[:controller] ||= @scope[:controller].to_s if @scope[:controller]
+ def defaults
+ @defaults ||= if to.respond_to?(:call)
+ { }
+ else
+ defaults = case to
+ when String
+ controller, action = to.split('#')
+ { :controller => controller, :action => action }
+ when Symbol
+ { :action => to.to_s }.merge(default_controller ? { :controller => default_controller } : {})
+ else
+ default_controller ? { :controller => default_controller } : {}
+ end
- app = initialize_app_endpoint(options, defaults)
- validate_defaults!(app, defaults, segment_keys)
- app = Constraints.new(app, blocks)
+ if defaults[:controller].blank? && segment_keys.exclude?("controller")
+ raise ArgumentError, "missing :controller"
+ end
- @set.add_route(app, conditions, requirements, defaults, options[:as])
+ if defaults[:action].blank? && segment_keys.exclude?("action")
+ raise ArgumentError, "missing :action"
+ end
- self
- end
+ defaults
+ end
+ end
- private
- def initialize_app_endpoint(options, defaults)
- app = nil
-
- if options[:to].respond_to?(:call)
- app = options[:to]
- defaults.delete(:controller)
- defaults.delete(:action)
- elsif options[:to].is_a?(String)
- defaults[:controller], defaults[:action] = options[:to].split('#')
- elsif options[:to].is_a?(Symbol)
- defaults[:action] = options[:to].to_s
+
+ def blocks
+ if @options[:constraints].present? && !@options[:constraints].is_a?(Hash)
+ block = @options[:constraints]
+ else
+ block = nil
end
- app || Routing::RouteSet::Dispatcher.new(:defaults => defaults)
+ ((@scope[:blocks] || []) + [ block ]).compact
end
- def validate_defaults!(app, defaults, segment_keys)
- return unless app.is_a?(Routing::RouteSet::Dispatcher)
+ def constraints
+ @constraints ||= requirements.reject { |k, v| segment_keys.include?(k.to_s) || k == :controller }
+ end
- unless defaults.include?(:controller) || segment_keys.include?("controller")
- raise ArgumentError, "missing :controller"
+ def request_method_condition
+ if via = @options[:via]
+ via = Array(via).map { |m| m.to_s.upcase }
+ { :request_method => Regexp.union(*via) }
+ else
+ { }
end
+ end
- unless defaults.include?(:action) || segment_keys.include?("action")
- raise ArgumentError, "missing :action"
- end
+ def segment_keys
+ @segment_keys ||= Rack::Mount::RegexpWithNamedGroups.new(
+ Rack::Mount::Strexp.compile(@path, requirements, SEPARATORS)
+ ).names
+ end
+
+ def to
+ @options[:to]
end
+
+ def default_controller
+ @scope[:controller].to_s if @scope[:controller]
+ end
+ end
+
+ module Base
+ def initialize(set)
+ @set = set
+ end
+
+ def root(options = {})
+ match '/', options.reverse_merge(:as => :root)
+ end
+
+ def match(*args)
+ @set.add_route(*Mapping.new(@set, @scope, args).to_route)
+ self
+ end
end
module HttpHelpers
@@ -132,13 +180,20 @@ module ActionDispatch
map_method(:delete, *args, &block)
end
- def redirect(path, options = {})
- status = options[:status] || 301
- lambda { |env|
- req = Rack::Request.new(env)
- url = req.scheme + '://' + req.host + path
- [status, {'Location' => url, 'Content-Type' => 'text/html'}, ['Moved Permanently']]
- }
+ def redirect(*args, &block)
+ options = args.last.is_a?(Hash) ? args.pop : {}
+
+ path = args.shift || block
+ path_proc = path.is_a?(Proc) ? path : proc { |params| path % params }
+ status = options[:status] || 301
+
+ lambda do |env|
+ req = Rack::Request.new(env)
+ params = path_proc.call(env["action_dispatch.request.path_parameters"])
+ url = req.scheme + '://' + req.host + params
+
+ [ status, {'Location' => url, 'Content-Type' => 'text/html'}, ['Moved Permanently'] ]
+ end
end
private
@@ -201,11 +256,11 @@ module ActionDispatch
self
ensure
- @scope[:path] = path if path_set
+ @scope[:path] = path if path_set
@scope[:name_prefix] = name_prefix if name_prefix_set
- @scope[:controller] = controller if controller_set
- @scope[:options] = options
- @scope[:blocks] = blocks
+ @scope[:controller] = controller if controller_set
+ @scope[:options] = options
+ @scope[:blocks] = blocks
@scope[:constraints] = constraints
end
@@ -301,12 +356,12 @@ module ActionDispatch
with_scope_level(:resource, resource) do
yield if block_given?
- get "(.:format)", :to => :show, :as => resource.member_name
- post "(.:format)", :to => :create
- put "(.:format)", :to => :update
- delete "(.:format)", :to => :destroy
- get "/new(.:format)", :to => :new, :as => "new_#{resource.singular}"
- get "/edit(.:format)", :to => :edit, :as => "edit_#{resource.singular}"
+ get "(.:format)", :to => :show, :as => resource.member_name
+ post "(.:format)", :to => :create
+ put "(.:format)", :to => :update
+ delete "(.:format)", :to => :destroy
+ get "/new(.:format)", :to => :new, :as => "new_#{resource.singular}"
+ get "/edit(.:format)", :to => :edit, :as => "edit_#{resource.singular}"
end
end
@@ -336,8 +391,9 @@ module ActionDispatch
yield if block_given?
with_scope_level(:collection) do
- get "(.:format)", :to => :index, :as => resource.collection_name
+ get "(.:format)", :to => :index, :as => resource.collection_name
post "(.:format)", :to => :create
+
with_exclusive_name_prefix :new do
get "/new(.:format)", :to => :new, :as => resource.singular
end
@@ -345,9 +401,10 @@ module ActionDispatch
with_scope_level(:member) do
scope("/:id") do
- get "(.:format)", :to => :show, :as => resource.member_name
- put "(.:format)", :to => :update
+ get "(.:format)", :to => :show, :as => resource.member_name
+ put "(.:format)", :to => :update
delete "(.:format)", :to => :destroy
+
with_exclusive_name_prefix :edit do
get "/edit(.:format)", :to => :edit, :as => resource.singular
end
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index bf2443c1be..bd397432ce 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -5,7 +5,7 @@ module ActionDispatch
module Routing
class RouteSet #:nodoc:
NotFound = lambda { |env|
- raise ActionController::RoutingError, "No route matches #{env['PATH_INFO'].inspect} with #{env.inspect}"
+ raise ActionController::RoutingError, "No route matches #{env['PATH_INFO'].inspect}"
}
PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
@@ -21,7 +21,7 @@ module ActionDispatch
prepare_params!(params)
unless controller = controller(params)
- return [417, {}, []]
+ return [404, {'X-Cascade' => 'pass'}, []]
end
controller.action(params[:action]).call(env)
@@ -273,7 +273,7 @@ module ActionDispatch
# TODO: Move this into Railties
if defined?(Rails.application)
# Find namespaces in controllers/ directory
- Rails.application.configuration.controller_paths.each do |load_path|
+ Rails.application.config.controller_paths.each do |load_path|
load_path = File.expand_path(load_path)
Dir["#{load_path}/**/*_controller.rb"].collect do |path|
namespaces << File.dirname(path).sub(/#{load_path}\/?/, '')
@@ -426,7 +426,7 @@ module ActionDispatch
end
end
- raise ActionController::RoutingError, "No route matches #{path.inspect} with #{environment.inspect}"
+ raise ActionController::RoutingError, "No route matches #{path.inspect}"
end
end
end
diff --git a/actionpack/lib/action_dispatch/testing/assertions/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb
index 9a917f704a..9c215de743 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/dom.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/dom.rb
@@ -1,3 +1,5 @@
+require 'action_controller/vendor/html-scanner'
+
module ActionDispatch
module Assertions
module DomAssertions
@@ -15,7 +17,7 @@ module ActionDispatch
assert_block(full_message) { expected_dom == actual_dom }
end
-
+
# The negated form of +assert_dom_equivalent+.
#
# ==== Examples
diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb
index 501a7c4dfb..5686bbdbde 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/response.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb
@@ -28,7 +28,7 @@ module ActionDispatch
assert_block("") { true } # to count the assertion
elsif type.is_a?(Fixnum) && @response.response_code == type
assert_block("") { true } # to count the assertion
- elsif type.is_a?(Symbol) && @response.response_code == ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[type]
+ elsif type.is_a?(Symbol) && @response.response_code == Rack::Utils::SYMBOL_TO_STATUS_CODE[type]
assert_block("") { true } # to count the assertion
else
assert_block(build_message(message, "Expected response to be a <?>, but was <?>", type, @response.response_code)) { false }
diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
index d22adfa749..c2dc591ff7 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
@@ -1,3 +1,5 @@
+require 'action_controller/vendor/html-scanner'
+
#--
# Copyright (c) 2006 Assaf Arkin (http://labnotes.org)
# Under MIT and/or CC By license.
@@ -16,7 +18,7 @@ module ActionDispatch
#
# Use +css_select+ to select elements without making an assertions, either
# from the response HTML or elements selected by the enclosing assertion.
- #
+ #
# In addition to HTML responses, you can make the following assertions:
# * +assert_select_rjs+ - Assertions on HTML content of RJS update and insertion operations.
# * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions.
@@ -53,8 +55,8 @@ module ActionDispatch
# end
#
# # Selects all list items in unordered lists
- # items = css_select("ul>li")
- #
+ # items = css_select("ul>li")
+ #
# # Selects all form tags and then all inputs inside the form
# forms = css_select("form")
# forms.each do |form|
@@ -212,7 +214,7 @@ module ActionDispatch
# Otherwise just operate on the response document.
root = response_from_page_or_rjs
end
-
+
# First or second argument is the selector: string and we pass
# all remaining arguments. Array and we pass the argument. Also
# accepts selector itself.
@@ -225,7 +227,7 @@ module ActionDispatch
selector = arg
else raise ArgumentError, "Expecting a selector as the first argument"
end
-
+
# Next argument is used for equality tests.
equals = {}
case arg = args.shift
@@ -315,10 +317,10 @@ module ActionDispatch
# Returns all matches elements.
matches
end
-
+
def count_description(min, max) #:nodoc:
pluralize = lambda {|word, quantity| word << (quantity == 1 ? '' : 's')}
-
+
if min && max && (max != min)
"between #{min} and #{max} elements"
elsif min && !(min == 1 && max == 1)
@@ -327,7 +329,7 @@ module ActionDispatch
"at most #{max} #{pluralize['element', max]}"
end
end
-
+
# :call-seq:
# assert_select_rjs(id?) { |elements| ... }
# assert_select_rjs(statement, id?) { |elements| ... }
@@ -344,7 +346,7 @@ module ActionDispatch
# that update or insert an element with that identifier.
#
# Use the first argument to narrow down assertions to only statements
- # of that type. Possible values are <tt>:replace</tt>, <tt>:replace_html</tt>,
+ # of that type. Possible values are <tt>:replace</tt>, <tt>:replace_html</tt>,
# <tt>:show</tt>, <tt>:hide</tt>, <tt>:toggle</tt>, <tt>:remove</tta>,
# <tt>:insert_html</tt> and <tt>:redirect</tt>.
#
@@ -494,7 +496,7 @@ module ActionDispatch
# end
# end
# end
- #
+ #
#
# # Selects all paragraph tags from within the description of an RSS feed
# assert_select_feed :rss, 2.0 do
diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
index b74dcb1fe4..5c735e61b2 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
@@ -1,3 +1,5 @@
+require 'action_controller/vendor/html-scanner'
+
module ActionDispatch
module Assertions
# Pair of assertions to testing elements in the HTML output of the response.
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 5c127dfe37..2a5f5dcd5c 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -411,7 +411,7 @@ module ActionDispatch
# At its simplest, you simply extend IntegrationTest and write your tests
# using the get/post methods:
#
- # require "#{File.dirname(__FILE__)}/test_helper"
+ # require "test_helper"
#
# class ExampleTest < ActionController::IntegrationTest
# fixtures :people
@@ -435,7 +435,7 @@ module ActionDispatch
# powerful testing DSL that is specific for your application. You can even
# reference any named routes you happen to have defined!
#
- # require "#{File.dirname(__FILE__)}/test_helper"
+ # require "test_helper"
#
# class AdvancedTest < ActionController::IntegrationTest
# fixtures :people, :rooms
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index c3e42ac0d5..8ce6e82524 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -23,7 +23,7 @@
activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
-require 'active_support'
+require 'active_support/ruby/shim'
require 'active_support/core_ext/class/attribute_accessors'
require 'action_pack'
@@ -31,29 +31,30 @@ require 'action_pack'
module ActionView
extend ActiveSupport::Autoload
- autoload :Base
- autoload :Context
- autoload :Template
- autoload :Helpers
- autoload :SafeBuffer
-
-
- autoload_under "render" do
- autoload :Partials
- autoload :Rendering
+ eager_autoload do
+ autoload :Context
+ autoload :Template
+ autoload :Helpers
+ autoload :SafeBuffer
+
+ autoload_under "render" do
+ autoload :Partials
+ autoload :Rendering
+ end
+
+ autoload :MissingTemplate, 'action_view/base'
+ autoload :Resolver, 'action_view/template/resolver'
+ autoload :PathResolver, 'action_view/template/resolver'
+ autoload :PathSet, 'action_view/paths'
+ autoload :FileSystemResolverWithFallback, 'action_view/template/resolver'
+
+ autoload :TemplateError, 'action_view/template/error'
+ autoload :TemplateHandler, 'action_view/template'
+ autoload :TemplateHandlers, 'action_view/template'
end
-
- autoload :MissingTemplate, 'action_view/base'
- autoload :Resolver, 'action_view/template/resolver'
- autoload :PathResolver, 'action_view/template/resolver'
- autoload :PathSet, 'action_view/paths'
- autoload :FileSystemResolverWithFallback, 'action_view/template/resolver'
-
- autoload :TemplateError, 'action_view/template/error'
- autoload :TemplateHandler, 'action_view/template'
- autoload :TemplateHandlers, 'action_view/template'
end
require 'action_view/erb/util'
+require 'action_view/base'
I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb
index 69d0d0fb67..f03ffe5ef4 100644
--- a/actionpack/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -1,3 +1,4 @@
+require 'action_controller/vendor/html-scanner'
require 'action_view/helpers/tag_helper'
module ActionView
diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb
index 564f12c955..35c431d78d 100644
--- a/actionpack/lib/action_view/helpers/translation_helper.rb
+++ b/actionpack/lib/action_view/helpers/translation_helper.rb
@@ -12,7 +12,7 @@ module ActionView
# prepend the key with a period, nothing is converted.
def translate(key, options = {})
options[:raise] = true
- I18n.translate(scope_key_by_partial(key), options)
+ I18n.translate(scope_key_by_partial(key), options).html_safe!
rescue I18n::MissingTranslationData => e
keys = I18n.send(:normalize_translation_keys, e.locale, e.key, e.options[:scope])
content_tag('span', keys.join(', '), :class => 'translation_missing')
diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb
index 7006a5b968..d4d16b4d98 100644
--- a/actionpack/lib/action_view/render/rendering.rb
+++ b/actionpack/lib/action_view/render/rendering.rb
@@ -78,12 +78,12 @@ module ActionView
end
def _render_inline(inline, layout, options)
- handler = Template.handler_class_for_extension(options[:type] || "erb")
- template = Template.new(options[:inline],
- "inline #{options[:inline].inspect}", handler, {})
+ handler = Template.handler_class_for_extension(options[:type] || "erb")
+ template = Template.new(options[:inline], "inline template", handler, {})
- locals = options[:locals]
+ locals = options[:locals]
content = template.render(self, locals)
+
_render_text(content, layout, locals)
end
@@ -91,6 +91,7 @@ module ActionView
content = layout.render(self, locals) do |*name|
_layout_for(*name) { content }
end if layout
+
content
end
@@ -113,21 +114,16 @@ module ActionView
msg
end
- locals = options[:locals] || {}
-
- content = if partial
- _render_partial_object(template, options)
- else
- template.render(self, locals)
- end
-
+ locals = options[:locals] || {}
+ content = partial ? _render_partial_object(template, options) : template.render(self, locals)
@_content_for[:layout] = content
if layout
@_layout = layout.identifier
logger.info("Rendering template within #{layout.inspect}") if logger
- content = layout.render(self, locals) {|*name| _layout_for(*name) }
+ content = layout.render(self, locals) { |*name| _layout_for(*name) }
end
+
content
end
end
diff --git a/actionpack/lib/action_view/safe_buffer.rb b/actionpack/lib/action_view/safe_buffer.rb
index 09f44ab26f..6be05b9e1e 100644
--- a/actionpack/lib/action_view/safe_buffer.rb
+++ b/actionpack/lib/action_view/safe_buffer.rb
@@ -1,4 +1,3 @@
-
module ActionView #:nodoc:
class SafeBuffer < String
def <<(value)
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 210ad508f5..d46c989d11 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -7,12 +7,14 @@ require "action_view/template/resolver"
module ActionView
class Template
extend ActiveSupport::Autoload
-
- autoload :Error
- autoload :Handler
- autoload :Handlers
- autoload :Text
-
+
+ eager_autoload do
+ autoload :Error
+ autoload :Handler
+ autoload :Handlers
+ autoload :Text
+ end
+
extend Template::Handlers
attr_reader :source, :identifier, :handler, :mime_type, :formats, :details
@@ -114,21 +116,6 @@ module ActionView
end
end
- class LocalsKey
- @hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } }
-
- def self.get(*locals)
- @hash_keys[*locals] ||= new(klass, format, locale)
- end
-
- attr_accessor :hash
- def initialize(klass, format, locale)
- @hash = locals.hash
- end
-
- alias_method :eql?, :equal?
- end
-
def build_method_name(locals)
# TODO: is locals.keys.hash reliably the same?
@method_names[locals.keys.hash] ||=
diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb
index f8e6376589..93a4315108 100644
--- a/actionpack/lib/action_view/template/handlers/erb.rb
+++ b/actionpack/lib/action_view/template/handlers/erb.rb
@@ -10,7 +10,8 @@ module ActionView
end
def add_text(src, text)
- src << "@output_buffer << ('" << escape_text(text) << "'.html_safe!);"
+ return if text.empty?
+ src << "@output_buffer.safe_concat('" << escape_text(text) << "');"
end
def add_expr_literal(src, code)