Fix routes with :controller segment when namespaced [#5034 state:resolved]

This commit is contained in:
José Valim
2010-07-02 19:13:00 +02:00
parent 0189fb76e3
commit 9e6e648732
4 changed files with 63 additions and 30 deletions

View File

@@ -91,7 +91,7 @@ module ActionDispatch
def app
Constraints.new(
to.respond_to?(:call) ? to : Routing::RouteSet::Dispatcher.new(:defaults => defaults),
to.respond_to?(:call) ? to : Routing::RouteSet::Dispatcher.new(:defaults => defaults, :module => @scope[:module]),
blocks,
@set.request_class
)

View File

@@ -14,6 +14,7 @@ module ActionDispatch
def initialize(options={})
@defaults = options[:defaults]
@glob_param = options.delete(:glob)
@module = options.delete(:module)
@controllers = {}
end
@@ -26,7 +27,7 @@ module ActionDispatch
return [404, {'X-Cascade' => 'pass'}, []]
end
controller.action(params[:action]).call(env)
dispatch(controller, params[:action], env)
end
def prepare_params!(params)
@@ -34,29 +35,44 @@ module ActionDispatch
split_glob_param!(params) if @glob_param
end
def controller(params, raise_error=true)
# If this is a default_controller (i.e. a controller specified by the user)
# we should raise an error in case it's not found, because it usually means
# an user error. However, if the controller was retrieved through a dynamic
# segment, as in :controller(/:action), we should simply return nil and
# delegate the control back to Rack cascade. Besides, if this is not a default
# controller, it means we should respect the @scope[:module] parameter.
def controller(params, default_controller=true)
if params && params.key?(:controller)
controller_param = params[:controller]
unless controller = @controllers[controller_param]
controller_name = "#{controller_param.camelize}Controller"
controller = @controllers[controller_param] =
ActiveSupport::Dependencies.ref(controller_name)
end
controller.get
controller_param = @module && !default_controller ?
"#{@module}/#{params[:controller]}" : params[:controller]
controller_reference(controller_param)
end
rescue NameError => e
raise ActionController::RoutingError, e.message, e.backtrace if raise_error
raise ActionController::RoutingError, e.message, e.backtrace if default_controller
end
private
def merge_default_action!(params)
params[:action] ||= 'index'
end
private
def split_glob_param!(params)
params[@glob_param] = params[@glob_param].split('/').map { |v| URI.unescape(v) }
def controller_reference(controller_param)
unless controller = @controllers[controller_param]
controller_name = "#{controller_param.camelize}Controller"
controller = @controllers[controller_param] =
ActiveSupport::Dependencies.ref(controller_name)
end
controller.get
end
def dispatch(controller, action, env)
controller.action(action).call(env)
end
def merge_default_action!(params)
params[:action] ||= 'index'
end
def split_glob_param!(params)
params[@glob_param] = params[@glob_param].split('/').map { |v| URI.unescape(v) }
end
end
# A NamedRouteCollection instance is a collection of named routes, and also

View File

@@ -182,13 +182,16 @@ class ActionController::IntegrationTest < ActiveSupport::TestCase
self.app = build_app
class StubDispatcher
def self.new(*args)
lambda { |env|
params = env['action_dispatch.request.path_parameters']
controller, action = params[:controller], params[:action]
[200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]]
}
# Stub Rails dispatcher so it does not get controller references and
# simply return the controller#action as Rack::Body.
class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher
protected
def controller_reference(controller_param)
controller_param
end
def dispatch(controller, action, env)
[200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]]
end
end

View File

@@ -310,11 +310,6 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
match '/' => 'mes#index'
end
namespace :private do
root :to => redirect('/private/index')
match "index", :to => 'private#index'
end
get "(/:username)/followers" => "followers#index"
get "/groups(/user/:username)" => "groups#index"
get "(/user/:username)/photos" => "photos#index"
@@ -348,6 +343,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
namespace :private do
root :to => redirect('/private/index')
match "index", :to => 'private#index'
match ":controller(/:action(/:id))"
end
match '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/
end
end
@@ -470,6 +471,19 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
def test_namespace_with_controller_segment
with_test_routes do
get '/private/foo'
assert_equal 'private/foo#index', @response.body
get '/private/foo/bar'
assert_equal 'private/foo#bar', @response.body
get '/private/foo/bar/1'
assert_equal 'private/foo#bar', @response.body
end
end
def test_session_singleton_resource
with_test_routes do
get '/session'