diff options
author | José Valim <jose.valim@gmail.com> | 2009-12-11 19:24:32 -0200 |
---|---|---|
committer | José Valim <jose.valim@gmail.com> | 2009-12-11 19:24:32 -0200 |
commit | cf7b94c013d4e824433a018001474e71ddd81a99 (patch) | |
tree | 67b90f1e13a88d60170469e281f081711a976194 /actionpack/lib/action_dispatch | |
parent | 6e55b32e98fcaad82184d2e21ee611a3465e4b20 (diff) | |
parent | 2297eaed5b195ea42b99d062ad45f87dde9d3c60 (diff) | |
download | rails-cf7b94c013d4e824433a018001474e71ddd81a99.tar.gz rails-cf7b94c013d4e824433a018001474e71ddd81a99.tar.bz2 rails-cf7b94c013d4e824433a018001474e71ddd81a99.zip |
Merge branch 'master' of git://github.com/rails/rails
Diffstat (limited to 'actionpack/lib/action_dispatch')
7 files changed, 389 insertions, 390 deletions
diff --git a/actionpack/lib/action_dispatch/http/status_codes.rb b/actionpack/lib/action_dispatch/http/status_codes.rb index 5bac842ec1..ea1475e827 100644 --- a/actionpack/lib/action_dispatch/http/status_codes.rb +++ b/actionpack/lib/action_dispatch/http/status_codes.rb @@ -21,22 +21,5 @@ module ActionDispatch hash[ActiveSupport::Inflector.underscore(message.gsub(/ /, "")).to_sym] = code hash }.freeze - - private - # Given a status parameter, determine whether it needs to be converted - # to a string. If it is a fixnum, use the STATUS_CODES hash to lookup - # the default message. If it is a symbol, use the SYMBOL_TO_STATUS_CODE - # hash to convert it. - def interpret_status(status) - case status - when Fixnum then - "#{status} #{STATUS_CODES[status]}".strip - when Symbol then - interpret_status(SYMBOL_TO_STATUS_CODE[status] || - "500 Unknown Status #{status.inspect}") - else - status.to_s - end - end end end diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 036deec6d2..471d18491c 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -2,8 +2,6 @@ require "active_support/core_ext/exception" module ActionDispatch class ShowExceptions - include StatusCodes - LOCALHOST = '127.0.0.1'.freeze RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates') @@ -29,7 +27,7 @@ module ActionDispatch 'ActionView::MissingTemplate' => 'missing_template', 'ActionController::RoutingError' => 'routing_error', ActionController::UnknownAction.name => 'unknown_action', - 'ActionView::TemplateError' => 'template_error' + 'ActionView::Template::Error' => 'template_error' }) FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'}, @@ -104,7 +102,7 @@ module ActionDispatch end def status_code(exception) - interpret_status(@@rescue_responses[exception.class.name]).to_i + ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[@@rescue_responses[exception.class.name]] end def render(status, body) @@ -119,7 +117,7 @@ module ActionDispatch return unless logger ActiveSupport::Deprecation.silence do - if ActionView::TemplateError === exception + if ActionView::Template::Error === exception logger.fatal(exception.to_s) else logger.fatal( diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 400039353c..d480af876d 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1,221 +1,193 @@ module ActionDispatch module Routing class Mapper - module Resources - class Resource #:nodoc: - attr_reader :plural, :singular - attr_reader :path_prefix, :name_prefix - - def initialize(entities, options = {}) - entities = entities.to_s - - @plural = entities.pluralize - @singular = entities.singularize - - @path_prefix = options[:path_prefix] - @name_prefix = options[:name_prefix] - end - - def name - plural - end - - def controller - plural + class Constraints + def self.new(app, constraints = []) + if constraints.any? + super(app, constraints) + else + app end + end - def member_name - if name_prefix - "#{name_prefix}_#{singular}" - else - singular - end - end + def initialize(app, constraints = []) + @app, @constraints = app, constraints + end - def collection_name - if name_prefix - "#{name_prefix}_#{plural}" - else - plural - end - end + def call(env) + req = Rack::Request.new(env) - def new_name - if name_prefix - "new_#{name_prefix}_#{singular}" - else - "new_#{singular}" + @constraints.each { |constraint| + if constraint.respond_to?(:matches?) && !constraint.matches?(req) + return [417, {}, []] + elsif constraint.respond_to?(:call) && !constraint.call(req) + return [417, {}, []] end - end + } - def edit_name - if name_prefix - "edit_#{name_prefix}_#{singular}" - else - "edit_#{singular}" - end - end + @app.call(env) end + end - class SingletonResource < Resource #:nodoc: - def initialize(entity, options = {}) - super(entity) - end + module Base + def initialize(set) + @set = set + end - def name - singular - end + def root(options = {}) + match '/', options.merge(:as => :root) end - def resource(*resources, &block) - options = resources.extract_options! + def match(*args) + options = args.extract_options! - if resources.length > 1 - raise ArgumentError if block_given? - resources.each { |r| resource(r, options) } - return self - end + path = args.first - name_prefix = @scope[:options][:name_prefix] if @scope[:options] - resource = SingletonResource.new(resources.pop, :name_prefix => name_prefix) + conditions, defaults = {}, {} - if @scope[:scope_level] == :resources - parent_resource = @scope[:scope_level_options][:name] - parent_named_prefix = @scope[:scope_level_options][:name_prefix] - with_scope_level(:member) do - scope(":#{parent_resource}_id", :name_prefix => parent_named_prefix) do - resource(resource.name, options, &block) - end - end - return self - end + path = nil if path == "" + path = "#{@scope[:path]}#{path}" if @scope[:path] + path = Rack::Mount::Utils.normalize_path(path) if path - controller(resource.controller) do - namespace(resource.name) do - with_scope_level(:resource, :name => resource.singular, :name_prefix => resource.member_name) do - yield if block_given? + raise ArgumentError, "path is required" unless path - get "", :to => :show, :as => resource.member_name - post "", :to => :create - put "", :to => :update - delete "", :to => :destroy - get "new", :to => :new, :as => resource.new_name - get "edit", :to => :edit, :as => resource.edit_name - end - end + constraints = options[:constraints] || {} + unless constraints.is_a?(Hash) + block, constraints = constraints, {} end + blocks = ((@scope[:blocks] || []) + [block]).compact + constraints = (@scope[:constraints] || {}).merge(constraints) + options.each { |k, v| constraints[k] = v if v.is_a?(Regexp) } - self - end + conditions[:path_info] = path + requirements = constraints.dup - def resources(*resources, &block) - options = resources.extract_options! - - if resources.length > 1 - raise ArgumentError if block_given? - resources.each { |r| resources(r, options) } - return self - end + path_regexp = Rack::Mount::Strexp.compile(path, constraints, SEPARATORS) + segment_keys = Rack::Mount::RegexpWithNamedGroups.new(path_regexp).names + constraints.reject! { |k, v| segment_keys.include?(k.to_s) } + conditions.merge!(constraints) - name_prefix = @scope[:options][:name_prefix] if @scope[:options] - resource = Resource.new(resources.pop, :name_prefix => name_prefix) + requirements[:controller] ||= @set.controller_constraints - if @scope[:scope_level] == :resources - parent_resource = @scope[:scope_level_options][:name] - parent_named_prefix = @scope[:scope_level_options][:name_prefix] - with_scope_level(:member) do - scope(":#{parent_resource}_id", :name_prefix => parent_named_prefix) do - resources(resource.name, options, &block) - end - end - return self + if via = options[:via] + via = Array(via).map { |m| m.to_s.upcase } + conditions[:request_method] = Regexp.union(*via) end - controller(resource.controller) do - namespace(resource.name) do - with_scope_level(:resources, :name => resource.singular, :name_prefix => resource.member_name) do - yield if block_given? + defaults[:controller] ||= @scope[:controller].to_s if @scope[:controller] - collection do - get "", :to => :index, :as => resource.collection_name - post "", :to => :create - get "new", :to => :new, :as => resource.new_name - end + app = initialize_app_endpoint(options, defaults) + validate_defaults!(app, defaults, segment_keys) + app = Constraints.new(app, blocks) - member do - get "", :to => :show, :as => resource.member_name - put "", :to => :update - delete "", :to => :destroy - get "edit", :to => :edit, :as => resource.edit_name - end - end - end - end + @set.add_route(app, conditions, requirements, defaults, options[:as]) self end - def collection - unless @scope[:scope_level] == :resources - raise ArgumentError, "can't use collection outside resources scope" - end + private + def initialize_app_endpoint(options, defaults) + app = nil + + if options[:to].respond_to?(:call) + app = options[:to] + defaults.delete(:controller) + defaults.delete(:action) + elsif options[:to].is_a?(String) + defaults[:controller], defaults[:action] = options[:to].split('#') + elsif options[:to].is_a?(Symbol) + defaults[:action] = options[:to].to_s + end - with_scope_level(:collection) do - yield + app || Routing::RouteSet::Dispatcher.new(:defaults => defaults) end - end - def member - unless @scope[:scope_level] == :resources - raise ArgumentError, "can't use member outside resources scope" - end + def validate_defaults!(app, defaults, segment_keys) + return unless app.is_a?(Routing::RouteSet::Dispatcher) - with_scope_level(:member) do - scope(":id") do - yield + unless defaults.include?(:controller) || segment_keys.include?("controller") + raise ArgumentError, "missing :controller" + end + + unless defaults.include?(:action) || segment_keys.include?("action") + raise ArgumentError, "missing :action" end end + end + + module HttpHelpers + def get(*args, &block) + map_method(:get, *args, &block) end - def match(*args) - options = args.extract_options! - args.push(options) + def post(*args, &block) + map_method(:post, *args, &block) + end - case options.delete(:on) - when :collection - return collection { match(*args) } - when :member - return member { match(*args) } - end + def put(*args, &block) + map_method(:put, *args, &block) + end - if @scope[:scope_level] == :resources - raise ArgumentError, "can't define route directly in resources scope" - end + def delete(*args, &block) + map_method(:delete, *args, &block) + end - super + def redirect(path, options = {}) + status = options[:status] || 301 + lambda { |env| + req = Rack::Request.new(env) + url = req.scheme + '://' + req.host + path + [status, {'Location' => url, 'Content-Type' => 'text/html'}, ['Moved Permanently']] + } end private - def with_scope_level(kind, options = {}) - old, @scope[:scope_level] = @scope[:scope_level], kind - old_options, @scope[:scope_level_options] = @scope[:scope_level_options], options - yield - ensure - @scope[:scope_level] = old - @scope[:scope_level_options] = old_options + def map_method(method, *args, &block) + options = args.extract_options! + options[:via] = method + args.push(options) + match(*args, &block) + self end end module Scoping - def self.extended(object) - object.instance_eval do - @scope = {} - end + def initialize(*args) + @scope = {} + super end def scope(*args) options = args.extract_options! + case args.first + when String + options[:path] = args.first + when Symbol + options[:controller] = args.first + end + + if path = options.delete(:path) + path_set = true + path, @scope[:path] = @scope[:path], Rack::Mount::Utils.normalize_path(@scope[:path].to_s + path.to_s) + else + path_set = false + end + + if name_prefix = options.delete(:name_prefix) + name_prefix_set = true + name_prefix, @scope[:name_prefix] = @scope[:name_prefix], (@scope[:name_prefix] ? "#{@scope[:name_prefix]}_#{name_prefix}" : name_prefix) + else + name_prefix_set = false + end + + if controller = options.delete(:controller) + controller_set = true + controller, @scope[:controller] = @scope[:controller], controller + else + controller_set = false + end + constraints = options.delete(:constraints) || {} unless constraints.is_a?(Hash) block, constraints = constraints, {} @@ -225,24 +197,12 @@ module ActionDispatch options, @scope[:options] = @scope[:options], (@scope[:options] || {}).merge(options) - path_set = controller_set = false - - case args.first - when String - path_set = true - path = args.first - path, @scope[:path] = @scope[:path], "#{@scope[:path]}#{Rack::Mount::Utils.normalize_path(path)}" - when Symbol - controller_set = true - controller = args.first - controller, @scope[:controller] = @scope[:controller], controller - end - yield self ensure @scope[:path] = path if path_set + @scope[:name_prefix] = name_prefix if name_prefix_set @scope[:controller] = controller if controller_set @scope[:options] = options @scope[:blocks] = blocks @@ -254,7 +214,7 @@ module ActionDispatch end def namespace(path) - scope(path.to_s) { yield } + scope("/#{path}") { yield } end def constraints(constraints = {}) @@ -263,172 +223,244 @@ module ActionDispatch def match(*args) options = args.extract_options! + options = (@scope[:options] || {}).merge(options) + + if @scope[:name_prefix] && !options[:as].blank? + options[:as] = "#{@scope[:name_prefix]}_#{options[:as]}" + elsif @scope[:name_prefix] && options[:as] == "" + options[:as] = @scope[:name_prefix].to_s + end + args.push(options) super(*args) end end - module HttpHelpers - def get(*args, &block) - map_method(:get, *args, &block) - end + module Resources + class Resource #:nodoc: + attr_reader :plural, :singular - def post(*args, &block) - map_method(:post, *args, &block) - end + def initialize(entities, options = {}) + entities = entities.to_s - def put(*args, &block) - map_method(:put, *args, &block) - end + @plural = entities.pluralize + @singular = entities.singularize + end - def delete(*args, &block) - map_method(:delete, *args, &block) - end + def name + plural + end - def redirect(path, options = {}) - status = options[:status] || 301 - lambda { |env| - req = Rack::Request.new(env) - url = req.scheme + '://' + req.host + path - [status, {'Location' => url, 'Content-Type' => 'text/html'}, ['Moved Permanently']] - } - end + def controller + plural + end - private - def map_method(method, *args, &block) - options = args.extract_options! - options[:via] = method - args.push(options) - match(*args, &block) - self + def member_name + singular end - end - class Constraints - def new(app, constraints = []) - if constraints.any? - super(app, constraints) - else - app + def collection_name + plural + end + + def id_segment + ":#{singular}_id" end end - def initialize(app, constraints = []) - @app, @constraints = app, constraints + class SingletonResource < Resource #:nodoc: + def initialize(entity, options = {}) + super + end + + def name + singular + end end - def call(env) - req = Rack::Request.new(env) + def resource(*resources, &block) + options = resources.extract_options! - @constraints.each { |constraint| - if constraint.respond_to?(:matches?) && !constraint.matches?(req) - return [417, {}, []] - elsif constraint.respond_to?(:call) && !constraint.call(req) - return [417, {}, []] + if resources.length > 1 + raise ArgumentError if block_given? + resources.each { |r| resource(r, options) } + return self + end + + resource = SingletonResource.new(resources.pop) + + if @scope[:scope_level] == :resources + nested do + resource(resource.name, options, &block) end - } + return self + end - @app.call(env) - end - end + scope(:path => "/#{resource.name}", :controller => resource.controller) do + with_scope_level(:resource, resource) do + yield if block_given? - def initialize(set) - @set = set + get "(.:format)", :to => :show, :as => resource.member_name + post "(.:format)", :to => :create + put "(.:format)", :to => :update + delete "(.:format)", :to => :destroy + get "/new(.:format)", :to => :new, :as => "new_#{resource.singular}" + get "/edit(.:format)", :to => :edit, :as => "edit_#{resource.singular}" + end + end - extend HttpHelpers - extend Scoping - extend Resources - end + self + end - def root(options = {}) - match '/', options.merge(:as => :root) - end + def resources(*resources, &block) + options = resources.extract_options! - def match(*args) - options = args.extract_options! + if resources.length > 1 + raise ArgumentError if block_given? + resources.each { |r| resources(r, options) } + return self + end - if args.length > 1 - args.each { |path| match(path, options) } - return self - end + resource = Resource.new(resources.pop) - if args.first.is_a?(Symbol) - return match(args.first.to_s, options.merge(:to => args.first.to_sym)) - end + if @scope[:scope_level] == :resources + nested do + resources(resource.name, options, &block) + end + return self + end - path = args.first + scope(:path => "/#{resource.name}", :controller => resource.controller) do + with_scope_level(:resources, resource) do + yield if block_given? - conditions, defaults = {}, {} + with_scope_level(:collection) do + get "(.:format)", :to => :index, :as => resource.collection_name + post "(.:format)", :to => :create + with_exclusive_name_prefix :new do + get "/new(.:format)", :to => :new, :as => resource.singular + end + end + + with_scope_level(:member) do + scope("/:id") do + get "(.:format)", :to => :show, :as => resource.member_name + put "(.:format)", :to => :update + delete "(.:format)", :to => :destroy + with_exclusive_name_prefix :edit do + get "/edit(.:format)", :to => :edit, :as => resource.singular + end + end + end + end + end - path = nil if path == "" - path = Rack::Mount::Utils.normalize_path(path) if path - path = "#{@scope[:path]}#{path}" if @scope[:path] + self + end - raise ArgumentError, "path is required" unless path + def collection + unless @scope[:scope_level] == :resources + raise ArgumentError, "can't use collection outside resources scope" + end - constraints = options[:constraints] || {} - unless constraints.is_a?(Hash) - block, constraints = constraints, {} + with_scope_level(:collection) do + scope(:name_prefix => parent_resource.collection_name, :as => "") do + yield + end + end end - blocks = ((@scope[:blocks] || []) + [block]).compact - constraints = (@scope[:constraints] || {}).merge(constraints) - options.each { |k, v| constraints[k] = v if v.is_a?(Regexp) } - conditions[:path_info] = path - requirements = constraints.dup + def member + unless @scope[:scope_level] == :resources + raise ArgumentError, "can't use member outside resources scope" + end - path_regexp = Rack::Mount::Strexp.compile(path, constraints, SEPARATORS) - segment_keys = Rack::Mount::RegexpWithNamedGroups.new(path_regexp).names - constraints.reject! { |k, v| segment_keys.include?(k.to_s) } - conditions.merge!(constraints) + with_scope_level(:member) do + scope("/:id", :name_prefix => parent_resource.member_name, :as => "") do + yield + end + end + end - requirements[:controller] ||= @set.controller_constraints + def nested + unless @scope[:scope_level] == :resources + raise ArgumentError, "can't use nested outside resources scope" + end - if via = options[:via] - via = Array(via).map { |m| m.to_s.upcase } - conditions[:request_method] = Regexp.union(*via) + with_scope_level(:nested) do + scope("/#{parent_resource.id_segment}", :name_prefix => parent_resource.member_name) do + yield + end + end end - defaults[:controller] ||= @scope[:controller].to_s if @scope[:controller] + def match(*args) + options = args.extract_options! - app = initialize_app_endpoint(options, defaults) - validate_defaults!(app, defaults, segment_keys) - app = Constraints.new(app, blocks) + if args.length > 1 + args.each { |path| match(path, options) } + return self + end - @set.add_route(app, conditions, requirements, defaults, options[:as]) + if args.first.is_a?(Symbol) + with_exclusive_name_prefix(args.first) do + return match("/#{args.first}(.:format)", options.merge(:to => args.first.to_sym)) + end + end - self - end + args.push(options) - private - def initialize_app_endpoint(options, defaults) - app = nil + case options.delete(:on) + when :collection + return collection { match(*args) } + when :member + return member { match(*args) } + end - if options[:to].respond_to?(:call) - app = options[:to] - defaults.delete(:controller) - defaults.delete(:action) - elsif options[:to].is_a?(String) - defaults[:controller], defaults[:action] = options[:to].split('#') - elsif options[:to].is_a?(Symbol) - defaults[:action] = options[:to].to_s + if @scope[:scope_level] == :resources + raise ArgumentError, "can't define route directly in resources scope" end - app || Routing::RouteSet::Dispatcher.new(:defaults => defaults) + super end - def validate_defaults!(app, defaults, segment_keys) - return unless app.is_a?(Routing::RouteSet::Dispatcher) + protected + def parent_resource + @scope[:scope_level_resource] + end - unless defaults.include?(:controller) || segment_keys.include?("controller") - raise ArgumentError, "missing :controller" + private + def with_exclusive_name_prefix(prefix) + begin + old_name_prefix = @scope[:name_prefix] + + if !old_name_prefix.blank? + @scope[:name_prefix] = "#{prefix}_#{@scope[:name_prefix]}" + else + @scope[:name_prefix] = prefix.to_s + end + + yield + ensure + @scope[:name_prefix] = old_name_prefix + end end - unless defaults.include?(:action) || segment_keys.include?("action") - raise ArgumentError, "missing :action" + def with_scope_level(kind, resource = parent_resource) + old, @scope[:scope_level] = @scope[:scope_level], kind + old_resource, @scope[:scope_level_resource] = @scope[:scope_level_resource], resource + yield + ensure + @scope[:scope_level] = old + @scope[:scope_level_resource] = old_resource end - end + end + + include Base + include HttpHelpers + include Scoping + include Resources end end end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index a8073c2105..8afd42a293 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -18,36 +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 - unless controller = controller(params) - return [417, {}, []] - end - - if env['action_controller.recognize'] - [200, {}, params] - else - 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 - rescue NameError - nil - end - def merge_default_action!(params) params[:action] ||= 'index' end @@ -216,7 +217,14 @@ module ActionDispatch def draw(&block) clear! - Mapper.new(self).instance_exec(DeprecatedMapper.new(self), &block) + + mapper = Mapper.new(self) + if block.arity == 1 + mapper.instance_exec(DeprecatedMapper.new(self), &block) + else + mapper.instance_exec(&block) + end + @set.add_route(NotFound) install_helpers @set.freeze @@ -426,7 +434,7 @@ module ActionDispatch raise ActionController::RoutingError, "No route matches #{options.inspect}" end - uri, params = result + path, params = result params.each do |k, v| if v params[k] = v @@ -435,16 +443,10 @@ module ActionDispatch end end - uri << "?#{params.to_query}" if uri && params.any? - path = uri - 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}" @@ -455,37 +457,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}) @@ -493,16 +469,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 diff --git a/actionpack/lib/action_dispatch/test_case.rb b/actionpack/lib/action_dispatch/test_case.rb new file mode 100644 index 0000000000..afd708f06f --- /dev/null +++ b/actionpack/lib/action_dispatch/test_case.rb @@ -0,0 +1,6 @@ +require "action_dispatch/testing/assertions" +require "action_dispatch/testing/integration" +require "action_dispatch/testing/performance_test" +require "action_dispatch/testing/test_request" +require "action_dispatch/testing/test_response" +require "action_dispatch/testing/integration"
\ No newline at end of file diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index e6d6b5a3ef..4bc5275e04 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -134,9 +134,11 @@ module ActionDispatch # Assume given controller request = ActionController::TestRequest.new request.env["REQUEST_METHOD"] = request_method.to_s.upcase if request_method - request.path = path + request.path = path + + params = ActionController::Routing::Routes.recognize_path(path, { :method => request.method }) + request.path_parameters = params.with_indifferent_access - ActionController::Routing::Routes.recognize(request) request end end diff --git a/actionpack/lib/action_dispatch/testing/performance_test.rb b/actionpack/lib/action_dispatch/testing/performance_test.rb index b1ed9d31f4..1b9a6c18b7 100644 --- a/actionpack/lib/action_dispatch/testing/performance_test.rb +++ b/actionpack/lib/action_dispatch/testing/performance_test.rb @@ -1,15 +1,17 @@ require 'active_support/testing/performance' require 'active_support/testing/default' -module ActionDispatch - # An integration test that runs a code profiler on your test methods. - # Profiling output for combinations of each test method, measurement, and - # output format are written to your tmp/performance directory. - # - # By default, process_time is measured and both flat and graph_html output - # formats are written, so you'll have two output files per test method. - class PerformanceTest < ActionDispatch::IntegrationTest - include ActiveSupport::Testing::Performance - include ActiveSupport::Testing::Default +if defined?(ActiveSupport::Testing::Performance) + module ActionDispatch + # An integration test that runs a code profiler on your test methods. + # Profiling output for combinations of each test method, measurement, and + # output format are written to your tmp/performance directory. + # + # By default, process_time is measured and both flat and graph_html output + # formats are written, so you'll have two output files per test method. + class PerformanceTest < ActionDispatch::IntegrationTest + include ActiveSupport::Testing::Performance + include ActiveSupport::Testing::Default + end end -end +end
\ No newline at end of file |