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/inspector.rb30
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb60
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb31
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb192
-rw-r--r--actionpack/lib/action_dispatch/routing/routes_proxy.rb9
5 files changed, 137 insertions, 185 deletions
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index cfe2237512..c513737fc2 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -28,23 +28,6 @@ module ActionDispatch
super.to_s
end
- def regexp
- __getobj__.path.to_regexp
- end
-
- def json_regexp
- str = regexp.inspect.
- sub('\\A' , '^').
- sub('\\Z' , '$').
- sub('\\z' , '$').
- sub(/^\// , '').
- sub(/\/[a-z]*$/ , '').
- gsub(/\(\?#.+\)/ , '').
- gsub(/\(\?-\w+:/ , '(').
- gsub(/\s/ , '')
- Regexp.new(str).source
- end
-
def reqs
@reqs ||= begin
reqs = endpoint
@@ -114,16 +97,13 @@ module ActionDispatch
def collect_routes(routes)
routes.collect do |route|
RouteWrapper.new(route)
- end.reject do |route|
- route.internal?
- end.collect do |route|
+ end.reject(&:internal?).collect do |route|
collect_engine_routes(route)
- { name: route.name,
- verb: route.verb,
- path: route.path,
- reqs: route.reqs,
- regexp: route.json_regexp }
+ { name: route.name,
+ verb: route.verb,
+ path: route.path,
+ reqs: route.reqs }
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index ac03ecb2c8..49009a45cc 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -4,11 +4,9 @@ require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/module/remove_method'
-require 'active_support/core_ext/string/filters'
require 'active_support/inflector'
require 'action_dispatch/routing/redirection'
require 'action_dispatch/routing/endpoint'
-require 'active_support/deprecation'
module ActionDispatch
module Routing
@@ -244,12 +242,10 @@ module ActionDispatch
def app(blocks)
if to.respond_to?(:call)
Constraints.new(to, blocks, false)
+ elsif blocks.any?
+ Constraints.new(dispatcher(defaults), blocks, true)
else
- if blocks.any?
- Constraints.new(dispatcher(defaults), blocks, true)
- else
- dispatcher(defaults)
- end
+ dispatcher(defaults)
end
end
@@ -281,22 +277,8 @@ module ActionDispatch
end
def split_to(to)
- case to
- when Symbol
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
- Defining a route where `to` is a symbol is deprecated.
- Please change `to: :#{to}` to `action: :#{to}`.
- MSG
-
- [nil, to.to_s]
- when /#/ then to.split('#')
- when String
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
- Defining a route where `to` is a controller without an action is deprecated.
- Please change `to: :#{to}` to `controller: :#{to}`.
- MSG
-
- [to, nil]
+ if to =~ /#/
+ to.split('#')
else
[]
end
@@ -391,7 +373,7 @@ module ActionDispatch
# Matches a url pattern to one or more routes.
#
- # You should not use the `match` method in your router
+ # You should not use the +match+ method in your router
# without specifying an HTTP method.
#
# If you want to expose your action to both GET and POST, use:
@@ -402,7 +384,7 @@ module ActionDispatch
# Note that +:controller+, +:action+ and +:id+ are interpreted as url
# query parameters and thus available through +params+ in an action.
#
- # If you want to expose your action to GET, use `get` in the router:
+ # If you want to expose your action to GET, use +get+ in the router:
#
# Instead of:
#
@@ -457,7 +439,7 @@ module ActionDispatch
# The route's action.
#
# [:param]
- # Overrides the default resource identifier `:id` (name of the
+ # 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>.
@@ -582,13 +564,7 @@ module ActionDispatch
raise "A rack application must be specified" unless path
rails_app = rails_app? app
-
- if rails_app
- options[:as] ||= app.railtie_name
- else
- # non rails apps can't have an :as
- options[:as] = nil
- end
+ options[:as] ||= app_name(app, rails_app)
target_as = name_for_action(options[:as], path)
options[:via] ||= :all
@@ -620,6 +596,15 @@ module ActionDispatch
app.is_a?(Class) && app < Rails::Railtie
end
+ def app_name(app, rails_app)
+ if rails_app
+ app.railtie_name
+ elsif app.is_a?(Class)
+ class_name = app.name
+ ActiveSupport::Inflector.underscore(class_name).tr("/", "_")
+ end
+ end
+
def define_generate_prefix(app, name)
_route = @set.named_routes.get name
_routes = @set
@@ -1519,7 +1504,7 @@ module ActionDispatch
end
def using_match_shorthand?(path, options)
- path && (options[:to] || options[:action]).nil? && path =~ %r{/[\w/]+$}
+ path && (options[:to] || options[:action]).nil? && path =~ %r{^/?[-\w]+/[-\w/]+$}
end
def decomposed_match(path, options) # :nodoc:
@@ -1693,7 +1678,7 @@ module ActionDispatch
end
def shallow_nesting_depth #:nodoc:
- @nesting.select(&:shallow?).size
+ @nesting.count(&:shallow?)
end
def param_constraint? #:nodoc:
@@ -1754,9 +1739,10 @@ module ActionDispatch
member_name = parent_resource.member_name
end
- name = @scope.action_name(name_prefix, prefix, collection_name, member_name)
+ action_name = @scope.action_name(name_prefix, prefix, collection_name, member_name)
+ candidate = action_name.select(&:present?).join('_')
- if candidate = name.compact.join("_").presence
+ unless candidate.empty?
# If a name was not explicitly given, we check if it is valid
# and return nil in case it isn't. Otherwise, we pass the invalid name
# forward so the underlying router engine treats it and raises an exception.
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
index 0847842fa2..9934f5547a 100644
--- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -1,5 +1,3 @@
-require 'action_controller/model_naming'
-
module ActionDispatch
module Routing
# Polymorphic URL helpers are methods for smart resolution to a named route call when
@@ -55,8 +53,6 @@ module ActionDispatch
# form_for([blog, @post]) # => "/blog/posts/1"
#
module PolymorphicRoutes
- include ActionController::ModelNaming
-
# Constructs a call to a named RESTful route for the given record and returns the
# resulting URL string. For example:
#
@@ -251,14 +247,12 @@ module ActionDispatch
args = []
model = record.to_model
- name = if record.persisted?
- args << model
- model.model_name.singular_route_key
- else
- @key_strategy.call model.model_name
- end
-
- named_route = prefix + "#{name}_#{suffix}"
+ named_route = if model.persisted?
+ args << model
+ get_method_for_string model.model_name.singular_route_key
+ else
+ get_method_for_class model
+ end
[named_route, args]
end
@@ -294,11 +288,12 @@ module ActionDispatch
when Class
@key_strategy.call record.model_name
else
- if record.persisted?
- args << record.to_model
- record.to_model.model_name.singular_route_key
+ model = record.to_model
+ if model.persisted?
+ args << model
+ model.model_name.singular_route_key
else
- @key_strategy.call record.to_model.model_name
+ @key_strategy.call model.model_name
end
end
@@ -312,11 +307,11 @@ module ActionDispatch
def get_method_for_class(klass)
name = @key_strategy.call klass.model_name
- prefix + "#{name}_#{suffix}"
+ get_method_for_string name
end
def get_method_for_string(str)
- prefix + "#{str}_#{suffix}"
+ "#{prefix}#{str}_#{suffix}"
end
[nil, 'new', 'edit'].each do |action|
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index a641ea3ea9..d0d8ded515 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -6,21 +6,21 @@ 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 'active_support/core_ext/string/filters'
require 'action_controller/metal/exceptions'
require 'action_dispatch/http/request'
require 'action_dispatch/routing/endpoint'
module ActionDispatch
module Routing
- class RouteSet #:nodoc:
+ # :stopdoc:
+ class RouteSet
# Since the router holds references to many parts of the system
# like engines, controllers and the application itself, inspecting
# the route set can actually be really slow, therefore we default
# alias inspect to to_s.
alias inspect to_s
- class Dispatcher < Routing::Endpoint #:nodoc:
+ class Dispatcher < Routing::Endpoint
def initialize(defaults)
@defaults = defaults
@controller_class_names = ThreadSafe::Cache.new
@@ -85,9 +85,9 @@ module ActionDispatch
# A NamedRouteCollection instance is a collection of named routes, and also
# maintains an anonymous module that can be used to install helpers for the
# named routes.
- class NamedRouteCollection #:nodoc:
+ class NamedRouteCollection
include Enumerable
- attr_reader :routes, :url_helpers_module
+ attr_reader :routes, :url_helpers_module, :path_helpers_module
def initialize
@routes = {}
@@ -102,14 +102,6 @@ module ActionDispatch
@path_helpers.include?(key) || @url_helpers.include?(key)
end
- def helpers
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
- `named_routes.helpers` is deprecated, please use `route_defined?(route_name)`
- to see if a named route was defined.
- MSG
- @path_helpers + @url_helpers
- end
-
def helper_names
@path_helpers.map(&:to_s) + @url_helpers.map(&:to_s)
end
@@ -138,7 +130,7 @@ module ActionDispatch
@url_helpers_module.send :undef_method, url_name
end
routes[key] = route
- define_url_helper @path_helpers_module, route, path_name, route.defaults, name, LEGACY
+ define_url_helper @path_helpers_module, route, path_name, route.defaults, name, PATH
define_url_helper @url_helpers_module, route, url_name, route.defaults, name, UNKNOWN
@path_helpers << path_name
@@ -170,26 +162,7 @@ module ActionDispatch
routes.length
end
- def path_helpers_module(warn = false)
- if warn
- mod = @path_helpers_module
- helpers = @path_helpers
- Module.new do
- include mod
-
- helpers.each do |meth|
- define_method(meth) do |*args, &block|
- ActiveSupport::Deprecation.warn("The method `#{meth}` cannot be used here as a full URL is required. Use `#{meth.to_s.sub(/_path$/, '_url')}` instead")
- super(*args, &block)
- end
- end
- end
- else
- @path_helpers_module
- end
- end
-
- class UrlHelper # :nodoc:
+ class UrlHelper
def self.create(route, options, route_name, url_strategy)
if optimize_helper?(route)
OptimizedUrlHelper.new(route, options, route_name, url_strategy)
@@ -204,7 +177,7 @@ module ActionDispatch
attr_reader :url_strategy, :route_name
- class OptimizedUrlHelper < UrlHelper # :nodoc:
+ class OptimizedUrlHelper < UrlHelper
attr_reader :arg_size
def initialize(route, options, route_name, url_strategy)
@@ -226,12 +199,9 @@ module ActionDispatch
private
def optimized_helper(args)
- params = parameterize_args(args)
- missing_keys = missing_keys(params)
-
- unless missing_keys.empty?
- raise_generation_error(params, missing_keys)
- end
+ params = parameterize_args(args) { |k|
+ raise_generation_error(args)
+ }
@route.format params
end
@@ -242,16 +212,21 @@ module ActionDispatch
def parameterize_args(args)
params = {}
- @required_parts.zip(args.map(&:to_param)) { |k,v| params[k] = v }
+ @arg_size.times { |i|
+ key = @required_parts[i]
+ value = args[i].to_param
+ yield key if value.nil? || value.empty?
+ params[key] = value
+ }
params
end
- def missing_keys(args)
- args.select{ |part, arg| arg.nil? || arg.empty? }.keys
- end
-
- def raise_generation_error(args, missing_keys)
- constraints = Hash[@route.requirements.merge(args).sort]
+ def raise_generation_error(args)
+ missing_keys = []
+ params = parameterize_args(args) { |missing_key|
+ missing_keys << missing_key
+ }
+ constraints = Hash[@route.requirements.merge(params).sort_by{|k,v| k.to_s}]
message = "No route matches #{constraints.inspect}"
message << " missing required keys: #{missing_keys.sort.inspect}"
@@ -280,15 +255,22 @@ module ActionDispatch
end
def handle_positional_args(controller_options, inner_options, args, result, path_params)
-
if args.size > 0
- if args.size < path_params.size - 1 # take format into account
+ # take format into account
+ if path_params.include?(:format)
+ path_params_size = path_params.size - 1
+ else
+ path_params_size = path_params.size
+ end
+
+ if args.size < path_params_size
path_params -= controller_options.keys
path_params -= result.keys
end
- path_params.each { |param|
- result[param] = inner_options[param] || args.shift
- }
+ path_params -= inner_options.keys
+ path_params.take(args.size).each do |param|
+ result[param] = args.shift
+ end
end
result.merge!(inner_options)
@@ -321,42 +303,14 @@ module ActionDispatch
end
end
- # :stopdoc:
# strategy for building urls to send to the client
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
- FULL = ->(options) { ActionDispatch::Http::URL.full_url_for(options) }
UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
- LEGACY = ->(options) {
- if options.key?(:only_path)
- if options[:only_path]
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
- You are calling a `*_path` helper with the `only_path` option
- explicitly set to `true`. This option will stop working on
- path helpers in Rails 5. Simply remove the `only_path: true`
- argument from your call as it is redundant when applied to a
- path helper.
- MSG
-
- PATH.call(options)
- else
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
- You are calling a `*_path` helper with the `only_path` option
- explicitly set to `false`. This option will stop working on
- path helpers in Rails 5. Use the corresponding `*_url` helper
- instead.
- MSG
-
- FULL.call(options)
- end
- else
- PATH.call(options)
- end
- }
- # :startdoc:
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
attr_accessor :disable_clear_and_finalize, :resources_path_names
- attr_accessor :default_url_options, :request_class
+ attr_accessor :default_url_options
+ attr_reader :env_key
alias :routes :set
@@ -364,22 +318,44 @@ module ActionDispatch
{ :new => 'new', :edit => 'edit' }
end
- def initialize(request_class = ActionDispatch::Request)
+ def self.new_with_config(config)
+ if config.respond_to? :relative_url_root
+ new Config.new config.relative_url_root
+ else
+ # engines apparently don't have this set
+ new
+ end
+ end
+
+ Config = Struct.new :relative_url_root
+
+ DEFAULT_CONFIG = Config.new(nil)
+
+ def initialize(config = DEFAULT_CONFIG)
self.named_routes = NamedRouteCollection.new
self.resources_path_names = self.class.default_resources_path_names
self.default_url_options = {}
- self.request_class = request_class
+ @config = config
@append = []
@prepend = []
@disable_clear_and_finalize = false
@finalized = false
+ @env_key = "ROUTES_#{object_id}_SCRIPT_NAME".freeze
@set = Journey::Routes.new
@router = Journey::Router.new @set
@formatter = Journey::Formatter.new @set
end
+ def relative_url_root
+ @config.relative_url_root
+ end
+
+ def request_class
+ ActionDispatch::Request
+ end
+
def draw(&block)
clear! unless @disable_clear_and_finalize
eval_block(block)
@@ -427,7 +403,7 @@ module ActionDispatch
Routing::RouteSet::Dispatcher.new(defaults)
end
- module MountedHelpers #:nodoc:
+ module MountedHelpers
extend ActiveSupport::Concern
include UrlFor
end
@@ -444,9 +420,11 @@ module ActionDispatch
return if MountedHelpers.method_defined?(name)
routes = self
+ helpers = routes.url_helpers
+
MountedHelpers.class_eval do
define_method "_#{name}" do
- RoutesProxy.new(routes, _routes_context)
+ RoutesProxy.new(routes, _routes_context, helpers)
end
end
@@ -457,7 +435,7 @@ module ActionDispatch
RUBY
end
- def url_helpers(include_path_helpers = true)
+ def url_helpers(supports_path = true)
routes = self
Module.new do
@@ -468,7 +446,14 @@ module ActionDispatch
# Rails.application.routes.url_helpers.url_for(args)
@_routes = routes
class << self
- delegate :url_for, :optimize_routes_generation?, to: '@_routes'
+ def url_for(options)
+ @_routes.url_for(options)
+ end
+
+ def optimize_routes_generation?
+ @_routes.optimize_routes_generation?
+ end
+
attr_reader :_routes
def url_options; {}; end
end
@@ -484,14 +469,12 @@ module ActionDispatch
# named routes...
include url_helpers
- if include_path_helpers
+ if supports_path
path_helpers = routes.named_routes.path_helpers_module
- else
- path_helpers = routes.named_routes.path_helpers_module(true)
- end
- include path_helpers
- extend path_helpers
+ include path_helpers
+ extend path_helpers
+ end
# plus a singleton class method called _routes ...
included do
@@ -502,6 +485,12 @@ module ActionDispatch
# UrlFor (included in this module) add extra
# conveniences for working with @_routes.
define_method(:_routes) { @_routes || routes }
+
+ define_method(:_generate_paths_by_default) do
+ supports_path
+ end
+
+ private :_generate_paths_by_default
end
end
@@ -523,7 +512,7 @@ module ActionDispatch
path = conditions.delete :path_info
ast = conditions.delete :parsed_path_info
path = build_path(path, ast, requirements, anchor)
- conditions = build_conditions(conditions, path.names.map { |x| x.to_sym })
+ conditions = build_conditions(conditions, path.names.map(&:to_sym))
route = @set.add_route(app, path, conditions, defaults, name)
named_routes[name] = route if name
@@ -575,17 +564,17 @@ module ActionDispatch
conditions.keep_if do |k, _|
k == :action || k == :controller || k == :required_defaults ||
- @request_class.public_method_defined?(k) || path_values.include?(k)
+ request_class.public_method_defined?(k) || path_values.include?(k)
end
end
private :build_conditions
- class Generator #:nodoc:
+ class Generator
PARAMETERIZE = lambda do |name, value|
if name == :controller
value
elsif value.is_a?(Array)
- value.map { |v| v.to_param }.join('/')
+ value.map(&:to_param).join('/')
elsif param = value.to_param
param
end
@@ -729,10 +718,10 @@ module ActionDispatch
end
def find_script_name(options)
- options.delete(:script_name) { '' }
+ options.delete(:script_name) || relative_url_root || ''
end
- def path_for(options, route_name = nil) # :nodoc:
+ def path_for(options, route_name = nil)
url_for(options, route_name, PATH)
end
@@ -818,5 +807,6 @@ module ActionDispatch
raise ActionController::RoutingError, "No route matches #{path.inspect}"
end
end
+ # :startdoc:
end
end
diff --git a/actionpack/lib/action_dispatch/routing/routes_proxy.rb b/actionpack/lib/action_dispatch/routing/routes_proxy.rb
index e2393d3799..040ea04046 100644
--- a/actionpack/lib/action_dispatch/routing/routes_proxy.rb
+++ b/actionpack/lib/action_dispatch/routing/routes_proxy.rb
@@ -8,8 +8,9 @@ module ActionDispatch
attr_accessor :scope, :routes
alias :_routes :routes
- def initialize(routes, scope)
+ def initialize(routes, scope, helpers)
@routes, @scope = routes, scope
+ @helpers = helpers
end
def url_options
@@ -19,16 +20,16 @@ module ActionDispatch
end
def respond_to?(method, include_private = false)
- super || routes.url_helpers.respond_to?(method)
+ super || @helpers.respond_to?(method)
end
def method_missing(method, *args)
- if routes.url_helpers.respond_to?(method)
+ if @helpers.respond_to?(method)
self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{method}(*args)
options = args.extract_options!
args << url_options.merge((options || {}).symbolize_keys)
- routes.url_helpers.#{method}(*args)
+ @helpers.#{method}(*args)
end
RUBY
send(method, *args)