diff options
-rw-r--r-- | actionpack/lib/action_dispatch/routing/mapper.rb | 92 | ||||
-rw-r--r-- | actionpack/test/dispatch/routing_test.rb | 32 |
2 files changed, 83 insertions, 41 deletions
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 4cf7adfb3c..8e7951729b 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -117,7 +117,7 @@ module ActionDispatch options[$1.to_sym] ||= /.+?/ end - if path_without_format.match(':controller') + if path_pattern.names.map(&:to_sym).include?(:controller) raise ArgumentError, ":controller segment is not allowed within a namespace block" if scope[:module] # Add a default constraint for :controller path segments that matches namespaced @@ -127,7 +127,11 @@ module ActionDispatch options[:controller] ||= /.+?/ end - options.merge!(default_controller_and_action) + if to.respond_to? :call + options + else + options.merge!(default_controller_and_action) + end end def normalize_requirements! @@ -237,54 +241,60 @@ module ActionDispatch end def default_controller_and_action - if to.respond_to?(:call) - { } - else - if to.is_a?(String) - controller, action = to.split('#') - elsif to.is_a?(Symbol) - action = to.to_s - end - - controller ||= default_controller - action ||= default_action - - if @scope[:module] && !controller.is_a?(Regexp) - if controller =~ %r{\A/} - controller = controller[1..-1] - else - controller = [@scope[:module], controller].compact.join("/").presence - end - end + controller, action = get_controller_and_action(default_controller, + default_action, + to, + @scope[:module] + ) + + hash = check_part(:controller, controller, {}) do |part| + translate_controller(part) { + message = "'#{part}' is not a supported controller name. This can lead to potential routing problems." + message << " See http://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use" - if controller.is_a?(String) && controller =~ %r{\A/} - raise ArgumentError, "controller name should not start with a slash" - end + raise ArgumentError, message + } + end - controller = controller.to_s unless controller.is_a?(Regexp) - action = action.to_s unless action.is_a?(Regexp) + check_part(:action, action, hash) { |part| + part.is_a?(Regexp) ? part : part.to_s + } + end - if controller.blank? && segment_keys.exclude?(:controller) - message = "Missing :controller key on routes definition, please check your routes." + def check_part(name, part, hash) + if part + hash[name] = yield(part) + else + unless segment_keys.include?(name) + message = "Missing :#{name} key on routes definition, please check your routes." raise ArgumentError, message end + end + hash + end - if action.blank? && segment_keys.exclude?(:action) - message = "Missing :action key on routes definition, please check your routes." - raise ArgumentError, message - end + def get_controller_and_action(controller, action, to, modyoule) + case to + when Symbol then action = to.to_s + when /#/ then controller, action = to.split('#') + when String then controller = to + end - if controller.is_a?(String) && controller !~ /\A[a-z_0-9\/]*\z/ - message = "'#{controller}' is not a supported controller name. This can lead to potential routing problems." - message << " See http://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use" - raise ArgumentError, message + if modyoule && !controller.is_a?(Regexp) + if controller =~ %r{\A/} + controller = controller[1..-1] + else + controller = [modyoule, controller].compact.join("/") end - - hash = {} - hash[:controller] = controller unless controller.blank? - hash[:action] = action unless action.blank? - hash end + [controller, action] + end + + def translate_controller(controller) + return controller if Regexp === controller + return controller.to_s if controller =~ /\A[a-z_0-9][a-z_0-9\/]*\z/ + + yield end def blocks diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index c9777ae71f..d6477e19bb 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -99,6 +99,16 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_namespace_without_controller_segment + draw do + namespace :admin do + get 'hello/:controllers/:action' + end + end + get '/admin/hello/foo/new' + assert_equal 'foo', @request.params["controllers"] + end + def test_session_singleton_resource draw do resource :session do @@ -3137,6 +3147,18 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal '/foo', foo_root_path end + def test_namespace_as_controller + draw do + namespace :foo do + get '/', to: '/bar#index', as: 'root' + end + end + + get '/foo' + assert_equal 'bar#index', @response.body + assert_equal '/foo', foo_root_path + end + def test_trailing_slash draw do resources :streams @@ -3546,6 +3568,16 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest assert_match "'Admin::StorageFiles' is not a supported controller name", e.message end + + def test_warn_with_ruby_constant_syntax_no_colons + e = assert_raise(ArgumentError) do + draw do + resources :storage_files, :controller => 'Admin' + end + end + + assert_match "'Admin' is not a supported controller name", e.message + end end class TestDefaultScope < ActionDispatch::IntegrationTest |