diff options
author | Mikel Lindsaar <raasdnil@gmail.com> | 2009-12-17 11:24:02 +1100 |
---|---|---|
committer | Mikel Lindsaar <raasdnil@gmail.com> | 2009-12-17 11:24:02 +1100 |
commit | 186cd7bc530f705b889c27f3680ab48c7c10a6f3 (patch) | |
tree | 76955e442615d77ee05ef2a8260c5373e1cac680 /actionpack/lib/action_dispatch/routing/route_set.rb | |
parent | 5f2395041d1578433fa825ed5c6f26a201f2203d (diff) | |
parent | b9d4ceb43c9497fb1c47d8b1e1e6a24a9e157384 (diff) | |
download | rails-186cd7bc530f705b889c27f3680ab48c7c10a6f3.tar.gz rails-186cd7bc530f705b889c27f3680ab48c7c10a6f3.tar.bz2 rails-186cd7bc530f705b889c27f3680ab48c7c10a6f3.zip |
Merge branch 'rails'
Conflicts:
actionmailer/lib/action_mailer.rb
actionmailer/lib/action_mailer/delivery_method/smtp.rb
Diffstat (limited to 'actionpack/lib/action_dispatch/routing/route_set.rb')
-rw-r--r-- | actionpack/lib/action_dispatch/routing/route_set.rb | 201 |
1 files changed, 89 insertions, 112 deletions
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 79e15edeaa..bf2443c1be 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -18,31 +18,37 @@ module ActionDispatch def call(env) params = env[PARAMETERS_KEY] + prepare_params!(params) + + unless controller = controller(params) + return [417, {}, []] + end + + controller.action(params[:action]).call(env) + end + + def prepare_params!(params) merge_default_action!(params) split_glob_param!(params) if @glob_param + params.each do |key, value| if value.is_a?(String) value = value.dup.force_encoding(Encoding::BINARY) if value.respond_to?(:force_encoding) params[key] = URI.unescape(value) end end + end - if env['action_controller.recognize'] - [200, {}, params] - else - controller = controller(params) - controller.action(params[:action]).call(env) + def controller(params) + if params && params.has_key?(:controller) + controller = "#{params[:controller].camelize}Controller" + ActiveSupport::Inflector.constantize(controller) end + rescue NameError + nil end private - def controller(params) - if params && params.has_key?(:controller) - controller = "#{params[:controller].camelize}Controller" - ActiveSupport::Inflector.constantize(controller) - end - end - def merge_default_action!(params) params[:action] ||= 'index' end @@ -197,26 +203,40 @@ module ActionDispatch end end - attr_accessor :routes, :named_routes, :configuration_files + attr_accessor :routes, :named_routes + attr_accessor :disable_clear_and_finalize def initialize - self.configuration_files = [] - self.routes = [] self.named_routes = NamedRouteCollection.new - clear! + @disable_clear_and_finalize = false end def draw(&block) - clear! - Mapper.new(self).instance_exec(DeprecatedMapper.new(self), &block) + clear! unless @disable_clear_and_finalize + + mapper = Mapper.new(self) + if block.arity == 1 + mapper.instance_exec(DeprecatedMapper.new(self), &block) + else + mapper.instance_exec(&block) + end + + finalize! unless @disable_clear_and_finalize + + nil + end + + def finalize! @set.add_route(NotFound) install_helpers @set.freeze end def clear! + # Clear the controller cache so we may discover new ones + @controller_constraints = nil routes.clear named_routes.clear @set = ::Rack::Mount::RouteSet.new(:parameters_key => PARAMETERS_KEY) @@ -231,65 +251,38 @@ module ActionDispatch routes.empty? end - def add_configuration_file(path) - self.configuration_files << path - end - - # Deprecated accessor - def configuration_file=(path) - add_configuration_file(path) - end - - # Deprecated accessor - def configuration_file - configuration_files - end - - def load! - # Clear the controller cache so we may discover new ones - Routing.clear_controller_cache! - - load_routes! - end - - # reload! will always force a reload whereas load checks the timestamp first - alias reload! load! + CONTROLLER_REGEXP = /[_a-zA-Z0-9]+/ - def reload - if configuration_files.any? && @routes_last_modified - if routes_changed_at == @routes_last_modified - return # routes didn't change, don't reload - else - @routes_last_modified = routes_changed_at - end - end - - load! - end - - def load_routes! - if configuration_files.any? - configuration_files.each { |config| load(config) } - @routes_last_modified = routes_changed_at - else - draw do |map| - map.connect ":controller/:action/:id" - end + def controller_constraints + @controller_constraints ||= begin + source = controller_namespaces.map { |ns| "#{Regexp.escape(ns)}/#{CONTROLLER_REGEXP.source}" } + source << CONTROLLER_REGEXP.source + Regexp.compile(source.sort.reverse.join('|')) end end - def routes_changed_at - routes_changed_at = nil + def controller_namespaces + namespaces = Set.new - configuration_files.each do |config| - config_changed_at = File.stat(config).mtime + # Find any nested controllers already in memory + ActionController::Base.subclasses.each do |klass| + controller_name = klass.underscore + namespaces << controller_name.split('/')[0...-1].join('/') + end - if routes_changed_at.nil? || config_changed_at > routes_changed_at - routes_changed_at = config_changed_at + # TODO: Move this into Railties + if defined?(Rails.application) + # Find namespaces in controllers/ directory + Rails.application.configuration.controller_paths.each do |load_path| + load_path = File.expand_path(load_path) + Dir["#{load_path}/**/*_controller.rb"].collect do |path| + namespaces << File.dirname(path).sub(/#{load_path}\/?/, '') + end end end - routes_changed_at + namespaces.delete('') + namespaces end def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil) @@ -374,7 +367,8 @@ module ActionDispatch end recall[:action] = options.delete(:action) if options[:action] == 'index' - parameterize = lambda { |name, value| + opts = {} + opts[:parameterize] = lambda { |name, value| if name == :controller value elsif value.is_a?(Array) @@ -384,14 +378,23 @@ module ActionDispatch end } - path = @set.url(named_route, options, recall, :parameterize => parameterize) + unless result = @set.generate(:path_info, named_route, options, recall, opts) + raise ActionController::RoutingError, "No route matches #{options.inspect}" + end + + path, params = result + params.each do |k, v| + if v + params[k] = v + else + params.delete(k) + end + end + if path && method == :generate_extras - uri = URI(path) - extras = uri.query ? - Rack::Utils.parse_nested_query(uri.query).keys.map { |k| k.to_sym } : - [] - [uri.path, extras] + [path, params.keys] elsif path + path << "?#{params.to_query}" if params.any? path else raise ActionController::RoutingError, "No route matches #{options.inspect}" @@ -402,37 +405,11 @@ module ActionDispatch def call(env) @set.call(env) - rescue ActionController::RoutingError => e - raise e if env['action_controller.rescue_error'] == false - - method, path = env['REQUEST_METHOD'].downcase.to_sym, env['PATH_INFO'] - - # Route was not recognized. Try to find out why (maybe wrong verb). - allows = HTTP_METHODS.select { |verb| - begin - recognize_path(path, {:method => verb}, false) - rescue ActionController::RoutingError - nil - end - } - - if !HTTP_METHODS.include?(method) - raise ActionController::NotImplemented.new(*allows) - elsif !allows.empty? - raise ActionController::MethodNotAllowed.new(*allows) - else - raise e - end - end - - def recognize(request) - params = recognize_path(request.path, extract_request_environment(request)) - request.path_parameters = params.with_indifferent_access - "#{params[:controller].to_s.camelize}Controller".constantize end - def recognize_path(path, environment = {}, rescue_error = true) + def recognize_path(path, environment = {}) method = (environment[:method] || "GET").to_s.upcase + path = Rack::Mount::Utils.normalize_path(path) begin env = Rack::MockRequest.env_for(path, {:method => method}) @@ -440,16 +417,16 @@ module ActionDispatch raise ActionController::RoutingError, e.message end - env['action_controller.recognize'] = true - env['action_controller.rescue_error'] = rescue_error - status, headers, body = call(env) - body - end + req = Rack::Request.new(env) + @set.recognize(req) do |route, params| + dispatcher = route.app + if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params) + dispatcher.prepare_params!(params) + return params + end + end - # Subclasses and plugins may override this method to extract further attributes - # from the request, for use by route conditions and such. - def extract_request_environment(request) - { :method => request.method } + raise ActionController::RoutingError, "No route matches #{path.inspect} with #{environment.inspect}" end end end |