From 9cc8c0a0a18163fb6ae0f66b2513c902d19459dc Mon Sep 17 00:00:00 2001 From: Brennan Dunn Date: Thu, 28 Aug 2008 07:53:29 -0400 Subject: [PATCH] Routes may be restricted to lists of HTTP methods instead of a single method or :any. [#407 state:resolved] Signed-off-by: Jeremy Kemper --- actionpack/CHANGELOG | 4 +++ .../lib/action_controller/routing/builder.rb | 12 +++++---- .../lib/action_controller/routing/route.rb | 2 +- actionpack/test/controller/routing_test.rb | 25 +++++++++++++++++++ 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 6717162d1e..7fdff1c8e0 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,9 @@ *Edge* +* Routes may be restricted to lists of HTTP methods instead of a single method or :any. #407 [Brennan Dunn, Gaius Centus Novus] + map.resource :posts, :collection => { :search => [:get, :post] } + map.session 'session', :requirements => { :method => [:get, :post, :delete] } + * Deprecated implicit local assignments when rendering partials [Josh Peek] * Introduce current_cycle helper method to return the current value without bumping the cycle. #417 [Ken Collins] diff --git a/actionpack/lib/action_controller/routing/builder.rb b/actionpack/lib/action_controller/routing/builder.rb index 03427e41de..5704d9d01a 100644 --- a/actionpack/lib/action_controller/routing/builder.rb +++ b/actionpack/lib/action_controller/routing/builder.rb @@ -187,12 +187,14 @@ module ActionController private def validate_route_conditions(conditions) if method = conditions[:method] - if method == :head - raise ArgumentError, "HTTP method HEAD is invalid in route conditions. Rails processes HEAD requests the same as GETs, returning just the response headers" - end + [method].flatten.each do |m| + if m == :head + raise ArgumentError, "HTTP method HEAD is invalid in route conditions. Rails processes HEAD requests the same as GETs, returning just the response headers" + end - unless HTTP_METHODS.include?(method.to_sym) - raise ArgumentError, "Invalid HTTP method specified in route conditions: #{conditions.inspect}" + unless HTTP_METHODS.include?(m.to_sym) + raise ArgumentError, "Invalid HTTP method specified in route conditions: #{conditions.inspect}" + end end end end diff --git a/actionpack/lib/action_controller/routing/route.rb b/actionpack/lib/action_controller/routing/route.rb index 2106ac09e0..3b2cb28545 100644 --- a/actionpack/lib/action_controller/routing/route.rb +++ b/actionpack/lib/action_controller/routing/route.rb @@ -201,7 +201,7 @@ module ActionController # recognition, not generation. def recognition_conditions result = ["(match = #{Regexp.new(recognition_pattern).inspect}.match(path))"] - result << "conditions[:method] === env[:method]" if conditions[:method] + result << "[conditions[:method]].flatten.include?(env[:method])" if conditions[:method] result end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 6cf134c26f..1a802c464f 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -1297,6 +1297,31 @@ uses_mocha 'LegacyRouteSet, Route, RouteSet and RouteLoading' do end end + def test_recognize_array_of_methods + begin + Object.const_set(:BooksController, Class.new(ActionController::Base)) + rs.draw do |r| + r.connect '/match', :controller => 'books', :action => 'get_or_post', :conditions => { :method => [:get, :post] } + r.connect '/match', :controller => 'books', :action => 'not_get_or_post' + end + + @request = ActionController::TestRequest.new + @request.env["REQUEST_METHOD"] = 'POST' + @request.request_uri = "/match" + assert_nothing_raised { rs.recognize(@request) } + assert_equal 'get_or_post', @request.path_parameters[:action] + + # have to recreate or else the RouteSet uses a cached version: + @request = ActionController::TestRequest.new + @request.env["REQUEST_METHOD"] = 'PUT' + @request.request_uri = "/match" + assert_nothing_raised { rs.recognize(@request) } + assert_equal 'not_get_or_post', @request.path_parameters[:action] + ensure + Object.send(:remove_const, :BooksController) rescue nil + end + end + def test_subpath_recognized Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))