aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/action_controller/base.rb64
-rw-r--r--actionpack/lib/action_controller/caching/pages.rb26
-rw-r--r--actionpack/lib/action_controller/dispatcher.rb1
-rw-r--r--actionpack/lib/action_controller/mime_type.rb22
-rw-r--r--actionpack/lib/action_controller/polymorphic_routes.rb2
-rwxr-xr-xactionpack/lib/action_controller/request.rb2
-rw-r--r--actionpack/lib/action_controller/request_forgery_protection.rb2
-rw-r--r--actionpack/lib/action_controller/resources.rb125
-rw-r--r--actionpack/lib/action_controller/routing.rb6
-rw-r--r--actionpack/lib/action_controller/routing/builder.rb53
-rw-r--r--actionpack/lib/action_controller/routing/recognition_optimisation.rb2
-rw-r--r--actionpack/lib/action_controller/routing/route.rb2
-rw-r--r--actionpack/lib/action_controller/routing/routing_ext.rb4
-rw-r--r--actionpack/lib/action_controller/routing/segments.rb28
-rw-r--r--actionpack/lib/action_controller/session/active_record_store.rb10
-rw-r--r--actionpack/lib/action_controller/test_process.rb1
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb2
-rw-r--r--actionpack/lib/action_pack/version.rb2
-rw-r--r--actionpack/lib/action_view/base.rb8
-rw-r--r--actionpack/lib/action_view/helpers/atom_feed_helper.rb13
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb10
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb4
-rw-r--r--actionpack/lib/action_view/template_handlers/erb.rb2
23 files changed, 270 insertions, 121 deletions
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 389ade425b..c1a56deca4 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -260,30 +260,44 @@ module ActionController #:nodoc:
include StatusCodes
- cattr_reader :protected_instance_variables
+ ##
+ # :singleton-method:
# Controller specific instance variables which will not be accessible inside views.
+ cattr_reader :protected_instance_variables
@@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 @_session @_cookies @_headers @_params
@_flash @_response)
+ @@asset_host = ""
+ ##
+ # :singleton-method:
# Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets,
# and images to a dedicated asset server away from the main web server. Example:
# ActionController::Base.asset_host = "http://assets.example.com"
- @@asset_host = ""
cattr_accessor :asset_host
+ @@consider_all_requests_local = true
+ ##
+ # :singleton-method:
# All requests are considered local by default, so everyone will be exposed to detailed debugging screens on errors.
# When the application is ready to go public, this should be set to false, and the protected method <tt>local_request?</tt>
# should instead be implemented in the controller to determine when debugging screens should be shown.
- @@consider_all_requests_local = true
cattr_accessor :consider_all_requests_local
+ @@allow_concurrency = false
+ ##
+ # :singleton-method:
# Indicates whether to allow concurrent action processing. Your
# controller actions and any other code they call must also behave well
# when called from concurrent threads. Turned off by default.
- @@allow_concurrency = false
cattr_accessor :allow_concurrency
+ @@param_parsers = { Mime::MULTIPART_FORM => :multipart_form,
+ Mime::URL_ENCODED_FORM => :url_encoded_form,
+ Mime::XML => :xml_simple,
+ Mime::JSON => :json }
+ ##
+ # :singleton-method:
# Modern REST web services often need to submit complex data to the web application.
# The <tt>@@param_parsers</tt> hash lets you register handlers which will process the HTTP body and add parameters to the
# <tt>params</tt> hash. These handlers are invoked for POST and PUT requests.
@@ -310,37 +324,47 @@ module ActionController #:nodoc:
# A YAML parser is also available and can be turned on with:
#
# ActionController::Base.param_parsers[Mime::YAML] = :yaml
- @@param_parsers = { Mime::MULTIPART_FORM => :multipart_form,
- Mime::URL_ENCODED_FORM => :url_encoded_form,
- Mime::XML => :xml_simple,
- Mime::JSON => :json }
cattr_accessor :param_parsers
- # Controls the default charset for all renders.
@@default_charset = "utf-8"
+ ##
+ # :singleton-method:
+ # Controls the default charset for all renders.
cattr_accessor :default_charset
+ ##
+ # :singleton-method:
# The logger is used for generating information on the action run-time (including benchmarking) if available.
# Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
cattr_accessor :logger
- # Controls the resource action separator
@@resource_action_separator = "/"
+ ##
+ # :singleton-method:
+ # Controls the resource action separator
cattr_accessor :resource_action_separator
- # Allow to override path names for default resources' actions
@@resources_path_names = { :new => 'new', :edit => 'edit' }
+ ##
+ # :singleton-method:
+ # Allow to override path names for default resources' actions
cattr_accessor :resources_path_names
+ ##
+ # :singleton-method:
# Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
# sets it to <tt>:authenticity_token</tt> by default.
cattr_accessor :request_forgery_protection_token
+ ##
+ # :singleton-method:
# Indicates whether or not optimise the generated named
# route helper methods
cattr_accessor :optimise_named_routes
self.optimise_named_routes = true
+ ##
+ # :singleton-method:
# Indicates whether the response format should be determined by examining the Accept HTTP header,
# or by using the simpler params + ajax rules.
#
@@ -351,38 +375,54 @@ module ActionController #:nodoc:
cattr_accessor :use_accept_header
self.use_accept_header = true
+ ##
+ # :singleton-method:
# Controls whether request forgergy protection is turned on or not. Turned off by default only in test mode.
class_inheritable_accessor :allow_forgery_protection
self.allow_forgery_protection = true
+ ##
+ # :singleton-method:
# If you are deploying to a subdirectory, you will need to set
# <tt>config.action_controller.relative_url_root</tt>
# This defaults to ENV['RAILS_RELATIVE_URL_ROOT']
cattr_accessor :relative_url_root
self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT']
+ ##
+ # :singleton-method:
# Holds the request object that's primarily used to get environment variables through access like
# <tt>request.env["REQUEST_URI"]</tt>.
attr_internal :request
+ ##
+ # :singleton-method:
# Holds a hash of all the GET, POST, and Url parameters passed to the action. Accessed like <tt>params["post_id"]</tt>
# to get the post_id. No type casts are made, so all values are returned as strings.
attr_internal :params
+ ##
+ # :singleton-method:
# Holds the response object that's primarily used to set additional HTTP headers through access like
# <tt>response.headers["Cache-Control"] = "no-cache"</tt>. Can also be used to access the final body HTML after a template
# has been rendered through response.body -- useful for <tt>after_filter</tt>s that wants to manipulate the output,
# such as a OutputCompressionFilter.
attr_internal :response
+ ##
+ # :singleton-method:
# Holds a hash of objects in the session. Accessed like <tt>session[:person]</tt> to get the object tied to the "person"
# key. The session will hold any type of object as values, but the key should be a string or symbol.
attr_internal :session
+ ##
+ # :singleton-method:
# Holds a hash of header names and values. Accessed like <tt>headers["Cache-Control"]</tt> to get the value of the Cache-Control
# directive. Values should always be specified as strings.
attr_internal :headers
+ ##
+ # :singleton-method:
# Returns the name of the action this controller is processing.
attr_accessor :action_name
@@ -1241,7 +1281,7 @@ module ActionController #:nodoc:
parameters = respond_to?(:filter_parameters) ? filter_parameters(params) : params.dup
parameters = parameters.except!(:controller, :action, :format, :_method)
- logger.info " Parameters: #{parameters.inspect}"
+ logger.info " Parameters: #{parameters.inspect}" unless parameters.empty?
end
def default_render #:nodoc:
diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb
index a70ed72f03..22e4fbec43 100644
--- a/actionpack/lib/action_controller/caching/pages.rb
+++ b/actionpack/lib/action_controller/caching/pages.rb
@@ -33,28 +33,26 @@ module ActionController #:nodoc:
#
# Additionally, you can expire caches using Sweepers that act on changes in the model to determine when a cache is supposed to be
# expired.
- #
- # == Setting the cache directory
- #
- # The cache directory should be the document root for the web server and is set using <tt>Base.page_cache_directory = "/document/root"</tt>.
- # For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>RAILS_ROOT + "/public"</tt>). Changing
- # this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your
- # web server to look in the new location for cached files.
- #
- # == Setting the cache extension
- #
- # Most Rails requests do not have an extension, such as <tt>/weblog/new</tt>. In these cases, the page caching mechanism will add one in
- # order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>.
- # If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an
- # extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps.
module Pages
def self.included(base) #:nodoc:
base.extend(ClassMethods)
base.class_eval do
@@page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : ""
+ ##
+ # :singleton-method:
+ # The cache directory should be the document root for the web server and is set using <tt>Base.page_cache_directory = "/document/root"</tt>.
+ # For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>RAILS_ROOT + "/public"</tt>). Changing
+ # this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your
+ # web server to look in the new location for cached files.
cattr_accessor :page_cache_directory
@@page_cache_extension = '.html'
+ ##
+ # :singleton-method:
+ # Most Rails requests do not have an extension, such as <tt>/weblog/new</tt>. In these cases, the page caching mechanism will add one in
+ # order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>.
+ # If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an
+ # extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps.
cattr_accessor :page_cache_extension
end
end
diff --git a/actionpack/lib/action_controller/dispatcher.rb b/actionpack/lib/action_controller/dispatcher.rb
index f3e173004a..2d5e80f0bb 100644
--- a/actionpack/lib/action_controller/dispatcher.rb
+++ b/actionpack/lib/action_controller/dispatcher.rb
@@ -23,7 +23,6 @@ module ActionController
if defined?(ActiveRecord)
after_dispatch :checkin_connections
- before_dispatch { ActiveRecord::Base.verify_active_connections! }
to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers }
end
diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb
index 26edca3b69..5ef52f45a6 100644
--- a/actionpack/lib/action_controller/mime_type.rb
+++ b/actionpack/lib/action_controller/mime_type.rb
@@ -20,8 +20,22 @@ module Mime
# end
class Type
@@html_types = Set.new [:html, :all]
+ cattr_reader :html_types
+
+ @@browser_generated_types = Set.new [:html, :url_encoded_form, :multipart_form]
+ ##
+ # :singleton-method:
+ # These are the content types which browsers can generate without using ajax, flash, etc
+ # i.e. following a link, getting an image or posting a form. CSRF protection
+ # only needs to protect against these types.
+ cattr_reader :browser_generated_types
+
+
@@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml]
- cattr_reader :html_types, :unverifiable_types
+ def self.unverifiable_types
+ ActiveSupport::Deprecation.warn("unverifiable_types is deprecated and has no effect", caller)
+ @@unverifiable_types
+ end
# A simple helper class used in parsing the accept header
class AcceptItem #:nodoc:
@@ -167,13 +181,17 @@ module Mime
# Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See
# ActionController::RequestForgerProtection.
def verify_request?
- !@@unverifiable_types.include?(to_sym)
+ browser_generated?
end
def html?
@@html_types.include?(to_sym) || @string =~ /html/
end
+ def browser_generated?
+ @@browser_generated_types.include?(to_sym)
+ end
+
private
def method_missing(method, *args)
if method.to_s =~ /(\w+)\?$/
diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb
index cc228c4230..2644c7f7c7 100644
--- a/actionpack/lib/action_controller/polymorphic_routes.rb
+++ b/actionpack/lib/action_controller/polymorphic_routes.rb
@@ -73,7 +73,7 @@ module ActionController
#
def polymorphic_url(record_or_hash_or_array, options = {})
if record_or_hash_or_array.kind_of?(Array)
- record_or_hash_or_array = record_or_hash_or_array.dup
+ record_or_hash_or_array = record_or_hash_or_array.compact
end
record = extract_record(record_or_hash_or_array)
diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb
index a6d4abf029..c079895683 100755
--- a/actionpack/lib/action_controller/request.rb
+++ b/actionpack/lib/action_controller/request.rb
@@ -13,7 +13,7 @@ module ActionController
ActiveSupport::Deprecation.warn(
"ActionController::AbstractRequest.relative_url_root= has been renamed." +
"You can now set it with config.action_controller.relative_url_root=", caller)
- ActionController::base.relative_url_root=relative_url_root
+ ActionController::Base.relative_url_root=relative_url_root
end
HTTP_METHODS = %w(get head put post delete options)
diff --git a/actionpack/lib/action_controller/request_forgery_protection.rb b/actionpack/lib/action_controller/request_forgery_protection.rb
index 05a6d8bb79..3e0e94a06b 100644
--- a/actionpack/lib/action_controller/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/request_forgery_protection.rb
@@ -99,7 +99,7 @@ module ActionController #:nodoc:
end
def verifiable_request_format?
- request.content_type.nil? || request.content_type.verify_request?
+ !request.content_type.nil? && request.content_type.verify_request?
end
# Sets the token value for the current session. Pass a <tt>:secret</tt> option
diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb
index 872b0dab3d..3b97916682 100644
--- a/actionpack/lib/action_controller/resources.rb
+++ b/actionpack/lib/action_controller/resources.rb
@@ -42,7 +42,11 @@ module ActionController
#
# Read more about REST at http://en.wikipedia.org/wiki/Representational_State_Transfer
module Resources
+ INHERITABLE_OPTIONS = :namespace, :shallow, :actions
+
class Resource #:nodoc:
+ DEFAULT_ACTIONS = :index, :create, :new, :edit, :show, :update, :destroy
+
attr_reader :collection_methods, :member_methods, :new_methods
attr_reader :path_prefix, :name_prefix, :path_segment
attr_reader :plural, :singular
@@ -57,6 +61,7 @@ module ActionController
arrange_actions
add_default_actions
+ set_allowed_actions
set_prefixes
end
@@ -113,6 +118,10 @@ module ActionController
@singular.to_s == @plural.to_s
end
+ def has_action?(action)
+ !DEFAULT_ACTIONS.include?(action) || @options[:actions].nil? || @options[:actions].include?(action)
+ end
+
protected
def arrange_actions
@collection_methods = arrange_actions_by_methods(options.delete(:collection))
@@ -125,6 +134,25 @@ module ActionController
add_default_action(new_methods, :get, :new)
end
+ def set_allowed_actions
+ only = @options.delete(:only)
+ except = @options.delete(:except)
+
+ if only && except
+ raise ArgumentError, 'Please supply either :only or :except, not both.'
+ elsif only == :all || except == :none
+ options[:actions] = DEFAULT_ACTIONS
+ elsif only == :none || except == :all
+ options[:actions] = []
+ elsif only
+ options[:actions] = DEFAULT_ACTIONS & Array(only).map(&:to_sym)
+ elsif except
+ options[:actions] = DEFAULT_ACTIONS - Array(except).map(&:to_sym)
+ else
+ # leave options[:actions] alone
+ end
+ end
+
def set_prefixes
@path_prefix = options.delete(:path_prefix)
@name_prefix = options.delete(:name_prefix)
@@ -255,7 +283,12 @@ module ActionController
# * <tt>:new</tt> - Same as <tt>:collection</tt>, but for actions that operate on the new \resource action.
# * <tt>:controller</tt> - Specify the controller name for the routes.
# * <tt>:singular</tt> - Specify the singular name used in the member routes.
- # * <tt>:requirements</tt> - Set custom routing parameter requirements.
+ # * <tt>:requirements</tt> - Set custom routing parameter requirements; this is a hash of either
+ # regular expressions (which must match for the route to match) or extra parameters. For example:
+ #
+ # map.resource :profile, :path_prefix => ':name', :requirements => { :name => /[a-zA-Z]+/, :extra => 'value' }
+ #
+ # will only match if the first part is alphabetic, and will pass the parameter :extra to the controller.
# * <tt>:conditions</tt> - Specify custom routing recognition conditions. \Resources sets the <tt>:method</tt> value for the method-specific routes.
# * <tt>:as</tt> - Specify a different \resource name to use in the URL path. For example:
# # products_path == '/productos'
@@ -353,6 +386,25 @@ module ActionController
#
# map.resources :users, :has_many => { :posts => :comments }, :shallow => true
#
+ # * <tt>:only</tt> and <tt>:except</tt> - Specify which of the seven default actions should be routed to.
+ #
+ # <tt>:only</tt> and <tt>:except</tt> may be set to <tt>:all</tt>, <tt>:none</tt>, an action name or a
+ # list of action names. By default, routes are generated for all seven actions.
+ #
+ # For example:
+ #
+ # map.resources :posts, :only => [:index, :show] do |post|
+ # post.resources :comments, :except => [:update, :destroy]
+ # end
+ # # --> GET /posts (maps to the PostsController#index action)
+ # # --> POST /posts (fails)
+ # # --> GET /posts/1 (maps to the PostsController#show action)
+ # # --> DELETE /posts/1 (fails)
+ # # --> POST /posts/1/comments (maps to the CommentsController#create action)
+ # # --> PUT /posts/1/comments/1 (fails)
+ #
+ # The <tt>:only</tt> and <tt>:except</tt> options are inherited by any nested resource(s).
+ #
# If <tt>map.resources</tt> is called with multiple resources, they all get the same options applied.
#
# Examples:
@@ -478,7 +530,7 @@ module ActionController
map_associations(resource, options)
if block_given?
- with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], &block)
+ with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
end
end
end
@@ -495,7 +547,7 @@ module ActionController
map_associations(resource, options)
if block_given?
- with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], &block)
+ with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
end
end
end
@@ -507,7 +559,7 @@ module ActionController
name_prefix = "#{options.delete(:name_prefix)}#{resource.nesting_name_prefix}"
Array(options[:has_one]).each do |association|
- resource(association, :path_prefix => path_prefix, :name_prefix => name_prefix, :namespace => options[:namespace], :shallow => options[:shallow])
+ resource(association, options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => path_prefix, :name_prefix => name_prefix))
end
end
@@ -522,7 +574,7 @@ module ActionController
map_has_many_associations(resource, association, options)
end
when Symbol, String
- resources(associations, :path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], :has_many => options[:has_many])
+ resources(associations, options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :has_many => options[:has_many]))
else
end
end
@@ -531,41 +583,39 @@ module ActionController
resource.collection_methods.each do |method, actions|
actions.each do |action|
[method].flatten.each do |m|
- action_options = action_options_for(action, resource, m)
- map_named_routes(map, "#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}", action_options)
+ map_resource_routes(map, resource, action, "#{resource.path}#{resource.action_separator}#{action}", "#{action}_#{resource.name_prefix}#{resource.plural}", m)
end
end
end
end
def map_default_collection_actions(map, resource)
- index_action_options = action_options_for("index", resource)
index_route_name = "#{resource.name_prefix}#{resource.plural}"
if resource.uncountable?
index_route_name << "_index"
end
- map_named_routes(map, index_route_name, resource.path, index_action_options)
-
- create_action_options = action_options_for("create", resource)
- map_unnamed_routes(map, resource.path, create_action_options)
+ map_resource_routes(map, resource, :index, resource.path, index_route_name)
+ map_resource_routes(map, resource, :create, resource.path, index_route_name)
end
def map_default_singleton_actions(map, resource)
- create_action_options = action_options_for("create", resource)
- map_unnamed_routes(map, resource.path, create_action_options)
+ map_resource_routes(map, resource, :create, resource.path, "#{resource.shallow_name_prefix}#{resource.singular}")
end
def map_new_actions(map, resource)
resource.new_methods.each do |method, actions|
actions.each do |action|
- action_options = action_options_for(action, resource, method)
- if action == :new
- map_named_routes(map, "new_#{resource.name_prefix}#{resource.singular}", resource.new_path, action_options)
- else
- map_named_routes(map, "#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}", action_options)
+ route_path = resource.new_path
+ route_name = "new_#{resource.name_prefix}#{resource.singular}"
+
+ unless action == :new
+ route_path = "#{route_path}#{resource.action_separator}#{action}"
+ route_name = "#{action}_#{route_name}"
end
+
+ map_resource_routes(map, resource, action, route_path, route_name, method)
end
end
end
@@ -574,34 +624,33 @@ module ActionController
resource.member_methods.each do |method, actions|
actions.each do |action|
[method].flatten.each do |m|
- action_options = action_options_for(action, resource, m)
-
action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
action_path ||= Base.resources_path_names[action] || action
- map_named_routes(map, "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}", action_options)
+ map_resource_routes(map, resource, action, "#{resource.member_path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", m)
end
end
end
- show_action_options = action_options_for("show", resource)
- map_named_routes(map, "#{resource.shallow_name_prefix}#{resource.singular}", resource.member_path, show_action_options)
-
- update_action_options = action_options_for("update", resource)
- map_unnamed_routes(map, resource.member_path, update_action_options)
-
- destroy_action_options = action_options_for("destroy", resource)
- map_unnamed_routes(map, resource.member_path, destroy_action_options)
- end
-
- def map_unnamed_routes(map, path_without_format, options)
- map.connect(path_without_format, options)
- map.connect("#{path_without_format}.:format", options)
+ route_path = "#{resource.shallow_name_prefix}#{resource.singular}"
+ map_resource_routes(map, resource, :show, resource.member_path, route_path)
+ map_resource_routes(map, resource, :update, resource.member_path, route_path)
+ map_resource_routes(map, resource, :destroy, resource.member_path, route_path)
end
- def map_named_routes(map, name, path_without_format, options)
- map.named_route(name, path_without_format, options)
- map.named_route("formatted_#{name}", "#{path_without_format}.:format", options)
+ def map_resource_routes(map, resource, action, route_path, route_name = nil, method = nil)
+ if resource.has_action?(action)
+ action_options = action_options_for(action, resource, method)
+ formatted_route_path = "#{route_path}.:format"
+
+ if route_name && @set.named_routes[route_name.to_sym].nil?
+ map.named_route(route_name, route_path, action_options)
+ map.named_route("formatted_#{route_name}", formatted_route_path, action_options)
+ else
+ map.connect(route_path, action_options)
+ map.connect(formatted_route_path, action_options)
+ end
+ end
end
def add_conditions_for(conditions, method)
diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb
index 8d51e823a6..2dcdac150a 100644
--- a/actionpack/lib/action_controller/routing.rb
+++ b/actionpack/lib/action_controller/routing.rb
@@ -84,9 +84,11 @@ module ActionController
# This sets up +blog+ as the default controller if no other is specified.
# This means visiting '/' would invoke the blog controller.
#
- # More formally, you can define defaults in a route with the <tt>:defaults</tt> key.
+ # More formally, you can include arbitrary parameters in the route, thus:
#
- # map.connect ':controller/:action/:id', :action => 'show', :defaults => { :page => 'Dashboard' }
+ # map.connect ':controller/:action/:id', :action => 'show', :page => 'Dashboard'
+ #
+ # This will pass the :page parameter to all incoming requests that match this route.
#
# Note: The default routes, as provided by the Rails generator, make all actions in every
# controller accessible via GET requests. You should consider removing them or commenting
diff --git a/actionpack/lib/action_controller/routing/builder.rb b/actionpack/lib/action_controller/routing/builder.rb
index 7b888fa8d2..d4e501e780 100644
--- a/actionpack/lib/action_controller/routing/builder.rb
+++ b/actionpack/lib/action_controller/routing/builder.rb
@@ -1,23 +1,16 @@
module ActionController
module Routing
class RouteBuilder #:nodoc:
- attr_accessor :separators, :optional_separators
+ attr_reader :separators, :optional_separators
+ attr_reader :separator_regexp, :nonseparator_regexp, :interval_regexp
def initialize
- self.separators = Routing::SEPARATORS
- self.optional_separators = %w( / )
- end
-
- def separator_pattern(inverted = false)
- "[#{'^' if inverted}#{Regexp.escape(separators.join)}]"
- end
-
- def interval_regexp
- Regexp.new "(.*?)(#{separators.source}|$)"
- end
+ @separators = Routing::SEPARATORS
+ @optional_separators = %w( / )
- def multiline_regexp?(expression)
- expression.options & Regexp::MULTILINE == Regexp::MULTILINE
+ @separator_regexp = /[#{Regexp.escape(separators.join)}]/
+ @nonseparator_regexp = /\A([^#{Regexp.escape(separators.join)}]+)/
+ @interval_regexp = /(.*?)(#{separator_regexp}|$)/
end
# Accepts a "route path" (a string defining a route), and returns the array
@@ -30,7 +23,7 @@ module ActionController
rest, segments = path, []
until rest.empty?
- segment, rest = segment_for rest
+ segment, rest = segment_for(rest)
segments << segment
end
segments
@@ -39,20 +32,20 @@ module ActionController
# A factory method that returns a new segment instance appropriate for the
# format of the given string.
def segment_for(string)
- segment = case string
- when /\A:(\w+)/
- key = $1.to_sym
- case key
- when :controller then ControllerSegment.new(key)
- else DynamicSegment.new key
- end
- when /\A\*(\w+)/ then PathSegment.new($1.to_sym, :optional => true)
- when /\A\?(.*?)\?/
- StaticSegment.new($1, :optional => true)
- when /\A(#{separator_pattern(:inverted)}+)/ then StaticSegment.new($1)
- when Regexp.new(separator_pattern) then
- DividerSegment.new($&, :optional => (optional_separators.include? $&))
- end
+ segment =
+ case string
+ when /\A:(\w+)/
+ key = $1.to_sym
+ key == :controller ? ControllerSegment.new(key) : DynamicSegment.new(key)
+ when /\A\*(\w+)/
+ PathSegment.new($1.to_sym, :optional => true)
+ when /\A\?(.*?)\?/
+ StaticSegment.new($1, :optional => true)
+ when nonseparator_regexp
+ StaticSegment.new($1)
+ when separator_regexp
+ DividerSegment.new($&, :optional => optional_separators.include?($&))
+ end
[segment, $~.post_match]
end
@@ -98,7 +91,7 @@ module ActionController
if requirement.source =~ %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
end
- if multiline_regexp?(requirement)
+ if requirement.multiline?
raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}"
end
segment.regexp = requirement
diff --git a/actionpack/lib/action_controller/routing/recognition_optimisation.rb b/actionpack/lib/action_controller/routing/recognition_optimisation.rb
index 6c47ced6d1..3b98b16683 100644
--- a/actionpack/lib/action_controller/routing/recognition_optimisation.rb
+++ b/actionpack/lib/action_controller/routing/recognition_optimisation.rb
@@ -148,7 +148,7 @@ module ActionController
end
nil
end
- }, __FILE__, __LINE__
+ }, '(recognize_optimized)', 1
end
def clear_recognize_optimized!
diff --git a/actionpack/lib/action_controller/routing/route.rb b/actionpack/lib/action_controller/routing/route.rb
index 3b2cb28545..a610ec7e84 100644
--- a/actionpack/lib/action_controller/routing/route.rb
+++ b/actionpack/lib/action_controller/routing/route.rb
@@ -219,7 +219,7 @@ module ActionController
next_capture = 1
extraction = segments.collect do |segment|
x = segment.match_extraction(next_capture)
- next_capture += Regexp.new(segment.regexp_chunk).number_of_captures
+ next_capture += segment.number_of_captures
x
end
extraction.compact
diff --git a/actionpack/lib/action_controller/routing/routing_ext.rb b/actionpack/lib/action_controller/routing/routing_ext.rb
index 5f4ba90d0c..4a82b2af5f 100644
--- a/actionpack/lib/action_controller/routing/routing_ext.rb
+++ b/actionpack/lib/action_controller/routing/routing_ext.rb
@@ -27,6 +27,10 @@ class Regexp #:nodoc:
Regexp.new("|#{source}").match('').captures.length
end
+ def multiline?
+ options & MULTILINE == MULTILINE
+ end
+
class << self
def optionalize(pattern)
case unoptionalize(pattern)
diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb
index e5f174ae2c..f6b03edcca 100644
--- a/actionpack/lib/action_controller/routing/segments.rb
+++ b/actionpack/lib/action_controller/routing/segments.rb
@@ -13,6 +13,10 @@ module ActionController
@is_optional = false
end
+ def number_of_captures
+ Regexp.new(regexp_chunk).number_of_captures
+ end
+
def extraction_code
nil
end
@@ -84,6 +88,10 @@ module ActionController
optional? ? Regexp.optionalize(chunk) : chunk
end
+ def number_of_captures
+ 0
+ end
+
def build_pattern(pattern)
escaped = Regexp.escape(value)
if optional? && ! pattern.empty?
@@ -194,10 +202,16 @@ module ActionController
end
end
+ def number_of_captures
+ if regexp
+ regexp.number_of_captures + 1
+ else
+ 1
+ end
+ end
+
def build_pattern(pattern)
- chunk = regexp_chunk
- chunk = "(#{chunk})" if Regexp.new(chunk).number_of_captures == 0
- pattern = "#{chunk}#{pattern}"
+ pattern = "#{regexp_chunk}#{pattern}"
optional? ? Regexp.optionalize(pattern) : pattern
end
@@ -230,6 +244,10 @@ module ActionController
"(?i-:(#{(regexp || Regexp.union(*possible_names)).source}))"
end
+ def number_of_captures
+ 1
+ end
+
# Don't URI.escape the controller name since it may contain slashes.
def interpolation_chunk(value_code = local_name)
"\#{#{value_code}.to_s}"
@@ -275,6 +293,10 @@ module ActionController
regexp || "(.*)"
end
+ def number_of_captures
+ regexp ? regexp.number_of_captures : 1
+ end
+
def optionality_implied?
true
end
diff --git a/actionpack/lib/action_controller/session/active_record_store.rb b/actionpack/lib/action_controller/session/active_record_store.rb
index 1e8eb57acb..fadf2a6b32 100644
--- a/actionpack/lib/action_controller/session/active_record_store.rb
+++ b/actionpack/lib/action_controller/session/active_record_store.rb
@@ -56,6 +56,8 @@ class CGI
class ActiveRecordStore
# The default Active Record class.
class Session < ActiveRecord::Base
+ ##
+ # :singleton-method:
# Customizable data column name. Defaults to 'data'.
cattr_accessor :data_column_name
self.data_column_name = 'data'
@@ -166,17 +168,25 @@ class CGI
# binary session data in a +text+ column. For higher performance,
# store in a +blob+ column instead and forgo the Base64 encoding.
class SqlBypass
+ ##
+ # :singleton-method:
# Use the ActiveRecord::Base.connection by default.
cattr_accessor :connection
+ ##
+ # :singleton-method:
# The table name defaults to 'sessions'.
cattr_accessor :table_name
@@table_name = 'sessions'
+ ##
+ # :singleton-method:
# The session id field defaults to 'session_id'.
cattr_accessor :session_id_column
@@session_id_column = 'session_id'
+ ##
+ # :singleton-method:
# The data field defaults to 'data'.
cattr_accessor :data_column
@@data_column = 'data'
diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb
index 7a31f0e8d5..1e3a646bc9 100644
--- a/actionpack/lib/action_controller/test_process.rb
+++ b/actionpack/lib/action_controller/test_process.rb
@@ -395,6 +395,7 @@ module ActionController #:nodoc:
@html_document = nil
@request.env['REQUEST_METHOD'] ||= "GET"
+
@request.action = action.to_s
parameters ||= {}
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 12c8405101..ae20f9947c 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
@@ -160,7 +160,7 @@ module HTML
if !options[:attributes].include?(attr_name) || contains_bad_protocols?(attr_name, value)
node.attributes.delete(attr_name)
else
- node.attributes[attr_name] = attr_name == 'style' ? sanitize_css(value) : CGI::escapeHTML(value)
+ node.attributes[attr_name] = attr_name == 'style' ? sanitize_css(value) : CGI::escapeHTML(CGI::unescapeHTML(value))
end
end
end
diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb
index 288b62778e..126d16e5f4 100644
--- a/actionpack/lib/action_pack/version.rb
+++ b/actionpack/lib/action_pack/version.rb
@@ -2,7 +2,7 @@ module ActionPack #:nodoc:
module VERSION #:nodoc:
MAJOR = 2
MINOR = 2
- TINY = 0
+ TINY = 1
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 945246a39a..a8ca0f685f 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -183,13 +183,17 @@ module ActionView #:nodoc:
@@exempt_from_layout.merge(regexps)
end
+ @@debug_rjs = false
+ ##
+ # :singleton-method:
# Specify whether RJS responses should be wrapped in a try/catch block
# that alert()s the caught exception (and then re-raises it).
- @@debug_rjs = false
cattr_accessor :debug_rjs
- # A warning will be displayed whenever an action results in a cache miss on your view paths.
@@warn_cache_misses = false
+ ##
+ # :singleton-method:
+ # A warning will be displayed whenever an action results in a cache miss on your view paths.
cattr_accessor :warn_cache_misses
attr_internal :request
diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
index ccb7df212a..cd25684940 100644
--- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb
+++ b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
@@ -1,3 +1,5 @@
+require 'set'
+
# Adds easy defaults to writing Atom feeds with the Builder template engine (this does not work on ERb or any other
# template languages).
module ActionView
@@ -121,6 +123,8 @@ module ActionView
end
class AtomBuilder
+ XHTML_TAG_NAMES = %w(content rights title subtitle summary).to_set
+
def initialize(xml)
@xml = xml
end
@@ -140,14 +144,15 @@ module ActionView
@xml.__send__(method, *arguments, &block)
end
end
-
+
# True if the method name matches one of the five elements defined
# in the Atom spec as potentially containing XHTML content and
# if :type => 'xhtml' is, in fact, specified.
def xhtml_block?(method, arguments)
- %w( content rights title subtitle summary ).include?(method.to_s) &&
- arguments.last.respond_to?(:[]) &&
- arguments.last[:type].to_s == 'xhtml'
+ if XHTML_TAG_NAMES.include?(method.to_s)
+ last = arguments.last
+ last.is_a?(Hash) && last[:type].to_s == 'xhtml'
+ end
end
end
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index de08672d2d..d37ca766af 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -133,10 +133,12 @@ module ActionView
unless options.blank?
attrs = []
if escape
- options.each do |key, value|
- next unless value
- value = BOOLEAN_ATTRIBUTES.include?(key) ? key : escape_once(value)
- attrs << %(#{key}="#{value}")
+ options.each_pair do |key, value|
+ if BOOLEAN_ATTRIBUTES.include?(key)
+ attrs << %(#{key}="#{key}") if value
+ else
+ attrs << %(#{key}="#{escape_once(value)}") if !value.nil?
+ end
end
else
attrs = options.map { |key, value| %(#{key}="#{value}") }
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index d80e7c6e57..36f7575652 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -559,7 +559,7 @@ module ActionView
(?:\.[-\w]+)* # remaining subdomains or domain
(?::\d+)? # port
(?:/(?:[~\w\+@%=\(\)-]|(?:[,.;:'][^\s$]))*)* # path
- (?:\?[\w\+@%&=.;-]+)? # query string
+ (?:\?[\w\+@%&=.;:-]+)? # query string
(?:\#[\w\-]*)? # trailing anchor
)
([[:punct:]]|<|$|) # trailing text
@@ -598,4 +598,4 @@ module ActionView
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template_handlers/erb.rb
index 3def949f1e..0fec1e0b18 100644
--- a/actionpack/lib/action_view/template_handlers/erb.rb
+++ b/actionpack/lib/action_view/template_handlers/erb.rb
@@ -42,6 +42,8 @@ module ActionView
class ERB < TemplateHandler
include Compilable
+ ##
+ # :singleton-method:
# Specify trim mode for the ERB compiler. Defaults to '-'.
# See ERb documentation for suitable values.
cattr_accessor :erb_trim_mode