aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_controller')
-rw-r--r--actionpack/lib/action_controller/base.rb6
-rw-r--r--actionpack/lib/action_controller/mime_type.rb20
-rw-r--r--actionpack/lib/action_controller/polymorphic_routes.rb2
-rw-r--r--actionpack/lib/action_controller/request_forgery_protection.rb2
-rw-r--r--actionpack/lib/action_controller/resources.rb118
-rw-r--r--actionpack/lib/action_controller/test_process.rb1
6 files changed, 105 insertions, 44 deletions
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 43f6c1be44..f35c42f929 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -1029,10 +1029,10 @@ module ActionController #:nodoc:
#
# * <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 starting with protocol:// (like http://)</tt> - Is passed straight through as the target for redirection.
- # * <tt>String not containing a protocol</tt> - The current protocol and host is prepended to the string.
+ # * <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 redirect_to(request.env["HTTP_REFERER"])
+ # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
#
# Examples:
# redirect_to :action => "show", :id => 5
diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb
index 26edca3b69..8ca3a70341 100644
--- a/actionpack/lib/action_controller/mime_type.rb
+++ b/actionpack/lib/action_controller/mime_type.rb
@@ -20,8 +20,20 @@ module Mime
# end
class Type
@@html_types = Set.new [:html, :all]
+ cattr_reader :html_types
+
+ # 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.
+ @@browser_generated_types = Set.new [:html, :url_encoded_form, :multipart_form]
+ 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 +179,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_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..7700b9d4d0 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)
@@ -353,6 +381,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 +525,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 +542,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 +554,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 +569,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 +578,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 +619,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/test_process.rb b/actionpack/lib/action_controller/test_process.rb
index 38e15baac2..28fb148e6e 100644
--- a/actionpack/lib/action_controller/test_process.rb
+++ b/actionpack/lib/action_controller/test_process.rb
@@ -394,6 +394,7 @@ module ActionController #:nodoc:
@html_document = nil
@request.env['REQUEST_METHOD'] ||= "GET"
+
@request.action = action.to_s
parameters ||= {}