aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/routing
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch/routing')
-rw-r--r--actionpack/lib/action_dispatch/routing/endpoint.rb10
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb15
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb112
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb245
-rw-r--r--actionpack/lib/action_dispatch/routing/redirection.rb20
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb158
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb6
7 files changed, 335 insertions, 231 deletions
diff --git a/actionpack/lib/action_dispatch/routing/endpoint.rb b/actionpack/lib/action_dispatch/routing/endpoint.rb
new file mode 100644
index 0000000000..88aa13c3e8
--- /dev/null
+++ b/actionpack/lib/action_dispatch/routing/endpoint.rb
@@ -0,0 +1,10 @@
+module ActionDispatch
+ module Routing
+ class Endpoint # :nodoc:
+ def dispatcher?; false; end
+ def redirect?; false; end
+ def matches?(req); true; end
+ def app; self; end
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index 71a0c5e826..ea3b2f419d 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -5,22 +5,15 @@ module ActionDispatch
module Routing
class RouteWrapper < SimpleDelegator
def endpoint
- rack_app ? rack_app.inspect : "#{controller}##{action}"
+ app.dispatcher? ? "#{controller}##{action}" : rack_app.inspect
end
def constraints
requirements.except(:controller, :action)
end
- def rack_app(app = self.app)
- @rack_app ||= begin
- class_name = app.class.name.to_s
- if class_name == "ActionDispatch::Routing::Mapper::Constraints"
- rack_app(app.app)
- elsif ActionDispatch::Routing::Redirect === app || class_name !~ /^ActionDispatch::Routing/
- app
- end
- end
+ def rack_app
+ app.app
end
def verb
@@ -73,7 +66,7 @@ module ActionDispatch
end
def engine?
- rack_app && rack_app.respond_to?(:routes)
+ rack_app.respond_to?(:routes)
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 4c20974ac7..4cf7adfb3c 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -6,6 +6,7 @@ require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/module/remove_method'
require 'active_support/inflector'
require 'action_dispatch/routing/redirection'
+require 'action_dispatch/routing/endpoint'
module ActionDispatch
module Routing
@@ -15,39 +16,46 @@ module ActionDispatch
:controller, :action, :path_names, :constraints,
:shallow, :blocks, :defaults, :options]
- class Constraints #:nodoc:
- def self.new(app, constraints, request = Rack::Request)
- if constraints.any?
- super(app, constraints, request)
- else
- app
+ class Constraints < Endpoint #:nodoc:
+ attr_reader :app, :constraints
+
+ def initialize(app, constraints, dispatcher_p)
+ # Unwrap Constraints objects. I don't actually think it's possible
+ # to pass a Constraints object to this constructor, but there were
+ # multiple places that kept testing children of this object. I
+ # *think* they were just being defensive, but I have no idea.
+ if app.is_a?(self.class)
+ constraints += app.constraints
+ app = app.app
end
- end
- attr_reader :app, :constraints
+ @dispatcher = dispatcher_p
- def initialize(app, constraints, request)
- @app, @constraints, @request = app, constraints, request
+ @app, @constraints, = app, constraints
end
- def matches?(env)
- req = @request.new(env)
+ def dispatcher?; @dispatcher; end
+ def matches?(req)
@constraints.all? do |constraint|
(constraint.respond_to?(:matches?) && constraint.matches?(req)) ||
(constraint.respond_to?(:call) && constraint.call(*constraint_args(constraint, req)))
end
- ensure
- req.reset_parameters
end
- def call(env)
- matches?(env) ? @app.call(env) : [ 404, {'X-Cascade' => 'pass'}, [] ]
+ def serve(req)
+ return [ 404, {'X-Cascade' => 'pass'}, [] ] unless matches?(req)
+
+ if dispatcher?
+ @app.serve req
+ else
+ @app.call req.env
+ end
end
private
def constraint_args(constraint, request)
- constraint.arity == 1 ? [request] : [request.symbolized_path_parameters, request]
+ constraint.arity == 1 ? [request] : [request.path_parameters, request]
end
end
@@ -57,12 +65,18 @@ module ActionDispatch
WILDCARD_PATH = %r{\*([^/\)]+)\)?$}
attr_reader :scope, :path, :options, :requirements, :conditions, :defaults
+ attr_reader :to, :default_controller, :default_action
def initialize(set, scope, path, options)
- @set, @scope, @path, @options = set, scope, path, options
+ @set, @scope, @path = set, scope, path
@requirements, @conditions, @defaults = {}, {}, {}
- normalize_options!
+ options = scope[:options].merge(options) if scope[:options]
+ @to = options[:to]
+ @default_controller = options[:controller] || scope[:controller]
+ @default_action = options[:action] || scope[:action]
+
+ @options = normalize_options!(options)
normalize_path!
normalize_requirements!
normalize_conditions!
@@ -94,14 +108,13 @@ module ActionDispatch
options[:format] != false && !path.include?(':format') && !path.end_with?('/')
end
- def normalize_options!
- @options.reverse_merge!(scope[:options]) if scope[:options]
+ def normalize_options!(options)
path_without_format = path.sub(/\(\.:format\)$/, '')
# Add a constraint for wildcard route to make it non-greedy and match the
# optional format part of the route by default
- if path_without_format.match(WILDCARD_PATH) && @options[:format] != false
- @options[$1.to_sym] ||= /.+?/
+ if path_without_format.match(WILDCARD_PATH) && options[:format] != false
+ options[$1.to_sym] ||= /.+?/
end
if path_without_format.match(':controller')
@@ -111,10 +124,10 @@ module ActionDispatch
# controllers with default routes like :controller/:action/:id(.:format), e.g:
# GET /admin/products/show/1
# => { controller: 'admin/products', action: 'show', id: '1' }
- @options[:controller] ||= /.+?/
+ options[:controller] ||= /.+?/
end
- @options.merge!(default_controller_and_action)
+ options.merge!(default_controller_and_action)
end
def normalize_requirements!
@@ -210,7 +223,17 @@ module ActionDispatch
end
def app
- Constraints.new(endpoint, blocks, @set.request_class)
+ return to if Redirect === to
+
+ if to.respond_to?(:call)
+ Constraints.new(to, blocks, false)
+ else
+ if blocks.any?
+ Constraints.new(dispatcher, blocks, true)
+ else
+ dispatcher
+ end
+ end
end
def default_controller_and_action
@@ -296,24 +319,8 @@ module ActionDispatch
Journey::Router::Strexp.compile(path, requirements, SEPARATORS)
end
- def endpoint
- to.respond_to?(:call) ? to : dispatcher
- end
-
def dispatcher
- Routing::RouteSet::Dispatcher.new(:defaults => defaults)
- end
-
- def to
- options[:to]
- end
-
- def default_controller
- options[:controller] || scope[:controller]
- end
-
- def default_action
- options[:action] || scope[:action]
+ Routing::RouteSet::Dispatcher.new(defaults)
end
end
@@ -415,6 +422,12 @@ module ActionDispatch
# [:action]
# The route's action.
#
+ # [:param]
+ # Overrides the default resource identifier `:id` (name of the
+ # dynamic segment used to generate the routes).
+ # You can access that segment from your controller using
+ # <tt>params[<:param>]</tt>.
+ #
# [:path]
# The path prefix for the routes.
#
@@ -578,18 +591,17 @@ module ActionDispatch
_route = @set.named_routes.routes[name.to_sym]
_routes = @set
app.routes.define_mounted_helper(name)
- app.routes.singleton_class.class_eval do
- redefine_method :mounted? do
- true
- end
-
- redefine_method :_generate_prefix do |options|
+ app.routes.extend Module.new {
+ def mounted?; true; end
+ define_method :find_script_name do |options|
+ super(options) || begin
prefix_options = options.slice(*_route.segment_keys)
# we must actually delete prefix segment keys to avoid passing them to next url_for
_route.segment_keys.each { |k| options.delete(k) }
_routes.url_helpers.send("#{name}_path", prefix_options)
+ end
end
- end
+ }
end
end
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
index b800ee6448..bd3696cda1 100644
--- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -101,58 +101,45 @@ module ActionDispatch
# polymorphic_url(Comment) # same as comments_url()
#
def polymorphic_url(record_or_hash_or_array, options = {})
- recipient = self
-
- if record_or_hash_or_array.kind_of?(Array)
- if record_or_hash_or_array.include? nil
- raise ArgumentError, "Nil location provided. Can't build URI."
- end
- record_or_hash_or_array = record_or_hash_or_array.dup
- if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy)
- recipient = record_or_hash_or_array.shift
- end
- record_or_hash_or_array = record_or_hash_or_array[0] if record_or_hash_or_array.size == 1
+ if Hash === record_or_hash_or_array
+ options = record_or_hash_or_array.merge(options)
+ record = options.delete :id
+ return polymorphic_url record, options
end
- record = extract_record(record_or_hash_or_array)
- record = convert_to_model(record)
-
- args = Array === record_or_hash_or_array ?
- record_or_hash_or_array.dup :
- [ record_or_hash_or_array ]
+ opts = options.dup
+ action = opts.delete :action
+ type = opts.delete(:routing_type) || :url
- inflection = if options[:action] && options[:action].to_s == "new"
- args.pop
- :singular
- elsif (record.respond_to?(:persisted?) && !record.persisted?)
- args.pop
- :plural
- elsif record.is_a?(Class)
- args.pop
- :plural
- else
- :singular
- end
-
- args.delete_if {|arg| arg.is_a?(Symbol) || arg.is_a?(String)}
- named_route = build_named_route_call(record_or_hash_or_array, record, inflection, options)
-
- url_options = options.except(:action, :routing_type)
- unless url_options.empty?
- args << url_options
- end
+ HelperMethodBuilder.polymorphic_method self,
+ record_or_hash_or_array,
+ action,
+ type,
+ opts
- args.collect! { |a| convert_to_model(a) }
-
- recipient.send(named_route, *args)
end
# Returns the path component of a URL for the given record. It uses
# <tt>polymorphic_url</tt> with <tt>routing_type: :path</tt>.
def polymorphic_path(record_or_hash_or_array, options = {})
- polymorphic_url(record_or_hash_or_array, options.merge(:routing_type => :path))
+ if Hash === record_or_hash_or_array
+ options = record_or_hash_or_array.merge(options)
+ record = options.delete :id
+ return polymorphic_path record, options
+ end
+
+ opts = options.dup
+ action = opts.delete :action
+ type = :path
+
+ HelperMethodBuilder.polymorphic_method self,
+ record_or_hash_or_array,
+ action,
+ type,
+ opts
end
+
%w(edit new).each do |action|
module_eval <<-EOT, __FILE__, __LINE__ + 1
def #{action}_polymorphic_url(record_or_hash, options = {}) # def edit_polymorphic_url(record_or_hash, options = {})
@@ -170,53 +157,169 @@ module ActionDispatch
end
private
- def action_prefix(options)
- options[:action] ? "#{options[:action]}_" : ''
+
+ class HelperMethodBuilder # :nodoc:
+ CACHE = { 'path' => {}, 'url' => {} }
+
+ def self.get(action, type)
+ type = type.to_s
+ CACHE[type].fetch(action) { build action, type }
+ end
+
+ def self.url; CACHE['url'.freeze][nil]; end
+ def self.path; CACHE['path'.freeze][nil]; end
+
+ def self.build(action, type)
+ prefix = action ? "#{action}_" : ""
+ suffix = type
+ if action.to_s == 'new'
+ HelperMethodBuilder.singular prefix, suffix
+ else
+ HelperMethodBuilder.plural prefix, suffix
+ end
end
- def routing_type(options)
- options[:routing_type] || :url
+ def self.singular(prefix, suffix)
+ new(->(name) { name.singular_route_key }, prefix, suffix)
end
- def build_named_route_call(records, record, inflection, options = {})
- if records.is_a?(Array)
- record = records.pop
- route = records.map do |parent|
- if parent.is_a?(Symbol) || parent.is_a?(String)
- parent
- else
- model_name_from_record_or_class(parent).singular_route_key
- end
+ def self.plural(prefix, suffix)
+ new(->(name) { name.route_key }, prefix, suffix)
+ end
+
+ def self.polymorphic_method(recipient, record_or_hash_or_array, action, type, options)
+ builder = get action, type
+
+ case record_or_hash_or_array
+ when Array
+ if record_or_hash_or_array.empty? || record_or_hash_or_array.include?(nil)
+ raise ArgumentError, "Nil location provided. Can't build URI."
+ end
+ if record_or_hash_or_array.first.is_a?(ActionDispatch::Routing::RoutesProxy)
+ recipient = record_or_hash_or_array.shift
end
+
+ method, args = builder.handle_list record_or_hash_or_array
+ when String, Symbol
+ method, args = builder.handle_string record_or_hash_or_array
+ when Class
+ method, args = builder.handle_class record_or_hash_or_array
+
+ when nil
+ raise ArgumentError, "Nil location provided. Can't build URI."
+ else
+ method, args = builder.handle_model record_or_hash_or_array
+ end
+
+
+ if options.empty?
+ recipient.send(method, *args)
else
- route = []
+ recipient.send(method, *args, options)
end
+ end
- if record.is_a?(Symbol) || record.is_a?(String)
- route << record
- elsif record
- if inflection == :singular
- route << model_name_from_record_or_class(record).singular_route_key
+ attr_reader :suffix, :prefix
+
+ def initialize(key_strategy, prefix, suffix)
+ @key_strategy = key_strategy
+ @prefix = prefix
+ @suffix = suffix
+ end
+
+ def handle_string(record)
+ [get_method_for_string(record), []]
+ end
+
+ def handle_string_call(target, str)
+ target.send get_method_for_string str
+ end
+
+ def handle_class(klass)
+ [get_method_for_class(klass), []]
+ end
+
+ def handle_class_call(target, klass)
+ target.send get_method_for_class klass
+ end
+
+ def handle_model(record)
+ args = []
+
+ model = record.to_model
+ name = if record.persisted?
+ args << model
+ model.class.model_name.singular_route_key
+ else
+ @key_strategy.call model.class.model_name
+ end
+
+ named_route = prefix + "#{name}_#{suffix}"
+
+ [named_route, args]
+ end
+
+ def handle_model_call(target, model)
+ method, args = handle_model model
+ target.send(method, *args)
+ end
+
+ def handle_list(list)
+ record_list = list.dup
+ record = record_list.pop
+
+ args = []
+
+ route = record_list.map { |parent|
+ case parent
+ when Symbol, String
+ parent.to_s
+ when Class
+ args << parent
+ parent.model_name.singular_route_key
else
- route << model_name_from_record_or_class(record).route_key
+ args << parent.to_model
+ parent.to_model.class.model_name.singular_route_key
end
+ }
+
+ route <<
+ case record
+ when Symbol, String
+ record.to_s
+ when Class
+ @key_strategy.call record.model_name
else
- raise ArgumentError, "Nil location provided. Can't build URI."
+ if record.persisted?
+ args << record.to_model
+ record.to_model.class.model_name.singular_route_key
+ else
+ @key_strategy.call record.to_model.class.model_name
+ end
end
- route << routing_type(options)
+ route << suffix
- action_prefix(options) + route.join("_")
+ named_route = prefix + route.join("_")
+ [named_route, args]
end
- def extract_record(record_or_hash_or_array)
- case record_or_hash_or_array
- when Array; record_or_hash_or_array.last
- when Hash; record_or_hash_or_array[:id]
- else record_or_hash_or_array
- end
+ private
+
+ def get_method_for_class(klass)
+ name = @key_strategy.call klass.model_name
+ prefix + "#{name}_#{suffix}"
+ end
+
+ def get_method_for_string(str)
+ prefix + "#{str}_#{suffix}"
end
+
+ [nil, 'new', 'edit'].each do |action|
+ CACHE['url'][action] = build action, 'url'
+ CACHE['path'][action] = build action, 'path'
+ end
+ end
end
end
end
-
diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb
index b08e62543b..b1b39a5496 100644
--- a/actionpack/lib/action_dispatch/routing/redirection.rb
+++ b/actionpack/lib/action_dispatch/routing/redirection.rb
@@ -3,10 +3,11 @@ require 'active_support/core_ext/uri'
require 'active_support/core_ext/array/extract_options'
require 'rack/utils'
require 'action_controller/metal/exceptions'
+require 'action_dispatch/routing/endpoint'
module ActionDispatch
module Routing
- class Redirect # :nodoc:
+ class Redirect < Endpoint # :nodoc:
attr_reader :status, :block
def initialize(status, block)
@@ -14,18 +15,15 @@ module ActionDispatch
@block = block
end
- def call(env)
- req = Request.new(env)
+ def redirect?; true; end
- # If any of the path parameters has an invalid encoding then
- # raise since it's likely to trigger errors further on.
- req.symbolized_path_parameters.each do |key, value|
- unless value.valid_encoding?
- raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}"
- end
- end
+ def call(env)
+ serve Request.new env
+ end
- uri = URI.parse(path(req.symbolized_path_parameters, req))
+ def serve(req)
+ req.check_path_parameters!
+ uri = URI.parse(path(req.path_parameters, req))
unless uri.host
if relative_path?(uri.path)
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 1ec6fa674b..3ca5abf0fd 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -1,11 +1,14 @@
require 'action_dispatch/journey'
require 'forwardable'
require 'thread_safe'
+require 'active_support/concern'
require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/module/remove_method'
require 'active_support/core_ext/array/extract_options'
require 'action_controller/metal/exceptions'
+require 'action_dispatch/http/request'
+require 'action_dispatch/routing/endpoint'
module ActionDispatch
module Routing
@@ -16,27 +19,17 @@ module ActionDispatch
# alias inspect to to_s.
alias inspect to_s
- PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
-
- class Dispatcher #:nodoc:
- def initialize(options={})
- @defaults = options[:defaults]
- @glob_param = options.delete(:glob)
+ class Dispatcher < Routing::Endpoint #:nodoc:
+ def initialize(defaults)
+ @defaults = defaults
@controller_class_names = ThreadSafe::Cache.new
end
- def call(env)
- params = env[PARAMETERS_KEY]
-
- # If any of the path parameters has an invalid encoding then
- # raise since it's likely to trigger errors further on.
- params.each do |key, value|
- next unless value.respond_to?(:valid_encoding?)
+ def dispatcher?; true; end
- unless value.valid_encoding?
- raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}"
- end
- end
+ def serve(req)
+ req.check_path_parameters!
+ params = req.path_parameters
prepare_params!(params)
@@ -45,13 +38,12 @@ module ActionDispatch
return [404, {'X-Cascade' => 'pass'}, []]
end
- dispatch(controller, params[:action], env)
+ dispatch(controller, params[:action], req.env)
end
def prepare_params!(params)
normalize_controller!(params)
merge_default_action!(params)
- split_glob_param!(params) if @glob_param
end
# If this is a default_controller (i.e. a controller specified by the user)
@@ -87,10 +79,6 @@ module ActionDispatch
def merge_default_action!(params)
params[:action] ||= 'index'
end
-
- def split_glob_param!(params)
- params[@glob_param] = params[@glob_param].split('/').map { |v| URI.parser.unescape(v) }
- end
end
# A NamedRouteCollection instance is a collection of named routes, and also
@@ -155,7 +143,7 @@ module ActionDispatch
end
def self.optimize_helper?(route)
- !route.glob? && route.requirements.except(:controller, :action).empty?
+ !route.glob? && route.path.requirements.empty?
end
class OptimizedUrlHelper < UrlHelper # :nodoc:
@@ -163,16 +151,13 @@ module ActionDispatch
def initialize(route, options)
super
- @klass = Journey::Router::Utils
@required_parts = @route.required_parts
@arg_size = @required_parts.size
- @optimized_path = @route.optimized_path
end
def call(t, args)
if args.size == arg_size && !args.last.is_a?(Hash) && optimize_routes_generation?(t)
- options = @options.dup
- options.merge!(t.url_options) if t.respond_to?(:url_options)
+ options = t.url_options.merge @options
options[:path] = optimized_helper(args)
ActionDispatch::Http::URL.url_for(options)
else
@@ -183,18 +168,14 @@ module ActionDispatch
private
def optimized_helper(args)
- params = Hash[parameterize_args(args)]
+ params = parameterize_args(args)
missing_keys = missing_keys(params)
unless missing_keys.empty?
raise_generation_error(params, missing_keys)
end
- @optimized_path.map{ |segment| replace_segment(params, segment) }.join
- end
-
- def replace_segment(params, segment)
- Symbol === segment ? @klass.escape_segment(params[segment]) : segment
+ @route.format params
end
def optimize_routes_generation?(t)
@@ -202,7 +183,9 @@ module ActionDispatch
end
def parameterize_args(args)
- @required_parts.zip(args.map(&:to_param))
+ params = {}
+ @required_parts.zip(args.map(&:to_param)) { |k,v| params[k] = v }
+ params
end
def missing_keys(args)
@@ -225,20 +208,23 @@ module ActionDispatch
end
def call(t, args)
- t.url_for(handle_positional_args(t, args, @options, @segment_keys))
+ controller_options = t.url_options
+ options = controller_options.merge @options
+ hash = handle_positional_args(controller_options, args, options, @segment_keys)
+ t._routes.url_for(hash)
end
- def handle_positional_args(t, args, options, keys)
+ def handle_positional_args(controller_options, args, result, path_params)
inner_options = args.extract_options!
- result = options.dup
if args.size > 0
- if args.size < keys.size - 1 # take format into account
- keys -= t.url_options.keys if t.respond_to?(:url_options)
- keys -= options.keys
+ if args.size < path_params.size - 1 # take format into account
+ path_params -= controller_options.keys
+ path_params -= result.keys
end
- keys -= inner_options.keys
- result.merge!(Hash[keys.zip(args)])
+ path_params.each { |param|
+ result[param] = inner_options[param] || args.shift
+ }
end
result.merge!(inner_options)
@@ -302,9 +288,7 @@ module ActionDispatch
@finalized = false
@set = Journey::Routes.new
- @router = Journey::Router.new(@set, {
- :parameters_key => PARAMETERS_KEY,
- :request_class => request_class})
+ @router = Journey::Router.new @set
@formatter = Journey::Formatter.new @set
end
@@ -393,6 +377,8 @@ module ActionDispatch
@_routes = routes
class << self
delegate :url_for, :optimize_routes_generation?, :to => '@_routes'
+ attr_reader :_routes
+ def url_options; {}; end
end
# Make named_routes available in the module singleton
@@ -594,7 +580,7 @@ module ActionDispatch
# Generates a path from routes, returns [path, params].
# If no route is generated the formatter will raise ActionController::UrlGenerationError
def generate
- @set.formatter.generate(:path_info, named_route, options, recall, PARAMETERIZE)
+ @set.formatter.generate(named_route, options, recall, PARAMETERIZE)
end
def different_controller?
@@ -639,41 +625,52 @@ module ActionDispatch
!mounted? && default_url_options.empty?
end
- def _generate_prefix(options = {})
- nil
+ def find_script_name(options)
+ options.delete :script_name
end
- # The +options+ argument must be +nil+ or a hash whose keys are *symbols*.
+ # The +options+ argument must be a hash whose keys are *symbols*.
def url_for(options)
- options = default_url_options.merge(options || {})
+ options = default_url_options.merge options
+
+ user = password = nil
- user, password = extract_authentication(options)
- recall = options.delete(:_recall)
+ if options[:user] && options[:password]
+ user = options.delete :user
+ password = options.delete :password
+ end
- original_script_name = options.delete(:original_script_name).presence
- script_name = options.delete(:script_name).presence || _generate_prefix(options)
+ recall = options.delete(:_recall) { {} }
+
+ original_script_name = options.delete(:original_script_name)
+ script_name = find_script_name options
if script_name && original_script_name
script_name = original_script_name + script_name
end
- path_options = options.except(*RESERVED_OPTIONS)
- path_options = yield(path_options) if block_given?
+ path_options = options.dup
+ RESERVED_OPTIONS.each { |ro| path_options.delete ro }
+
+ path, params = generate(path_options, recall)
+
+ if options.key? :params
+ params.merge! options[:params]
+ end
- path, params = generate(path_options, recall || {})
- params.merge!(options[:params] || {})
+ options[:path] = path
+ options[:script_name] = script_name
+ options[:params] = params
+ options[:user] = user
+ options[:password] = password
- ActionDispatch::Http::URL.url_for(options.merge!({
- :path => path,
- :script_name => script_name,
- :params => params,
- :user => user,
- :password => password
- }))
+ ActionDispatch::Http::URL.url_for(options)
end
def call(env)
- @router.call(env)
+ req = request_class.new(env)
+ req.path_info = Journey::Router::Utils.normalize_path(req.path_info)
+ @router.serve(req)
end
def recognize_path(path, environment = {})
@@ -687,8 +684,8 @@ module ActionDispatch
raise ActionController::RoutingError, e.message
end
- req = @request_class.new(env)
- @router.recognize(req) do |route, _matches, params|
+ req = request_class.new(env)
+ @router.recognize(req) do |route, params|
params.merge!(extras)
params.each do |key, value|
if value.is_a?(String)
@@ -696,14 +693,12 @@ module ActionDispatch
params[key] = URI.parser.unescape(value)
end
end
- old_params = env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
- env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] = (old_params || {}).merge(params)
- dispatcher = route.app
- while dispatcher.is_a?(Mapper::Constraints) && dispatcher.matches?(env) do
- dispatcher = dispatcher.app
- end
+ old_params = req.path_parameters
+ req.path_parameters = old_params.merge params
+ app = route.app
+ if app.matches?(req) && app.dispatcher?
+ dispatcher = app.app
- if dispatcher.is_a?(Dispatcher)
if dispatcher.controller(params, false)
dispatcher.prepare_params!(params)
return params
@@ -715,17 +710,6 @@ module ActionDispatch
raise ActionController::RoutingError, "No route matches #{path.inspect}"
end
-
- private
-
- def extract_authentication(options)
- if options[:user] && options[:password]
- [options.delete(:user), options.delete(:password)]
- else
- nil
- end
- end
-
end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index 4a0ef40873..e624fe3c4a 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -155,10 +155,14 @@ module ActionDispatch
_routes.url_for(options.symbolize_keys.reverse_merge!(url_options))
when String
options
+ when Symbol
+ HelperMethodBuilder.url.handle_string_call self, options
when Array
polymorphic_url(options, options.extract_options!)
+ when Class
+ HelperMethodBuilder.url.handle_class_call self, options
else
- polymorphic_url(options)
+ HelperMethodBuilder.url.handle_model_call self, options
end
end