diff options
Diffstat (limited to 'actionpack/lib/action_dispatch/routing')
-rw-r--r-- | actionpack/lib/action_dispatch/routing/mapper.rb | 21 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/routing/route_set.rb | 44 |
2 files changed, 57 insertions, 8 deletions
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 07e3be4db8..8b5a39dcaf 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -50,7 +50,19 @@ module ActionDispatch private def constraint_args(constraint, request) - constraint.arity == 1 ? [request] : [request.path_parameters, request] + arity = if constraint.respond_to?(:arity) + constraint.arity + else + constraint.method(:call).arity + end + + if arity < 1 + [] + elsif arity == 1 + [request] + else + [request.path_parameters, request] + end end end @@ -308,7 +320,7 @@ module ActionDispatch def check_controller_and_action(path_params, controller, action) hash = check_part(:controller, controller, path_params, {}) do |part| translate_controller(part) { - message = "'#{part}' is not a supported controller name. This can lead to potential routing problems.".dup + message = +"'#{part}' is not a supported controller name. This can lead to potential routing problems." message << " See https://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use" raise ArgumentError, message @@ -390,7 +402,7 @@ module ActionDispatch # for root cases, where the latter is the correct one. def self.normalize_path(path) path = Journey::Router::Utils.normalize_path(path) - path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/\(+[^)]+\)$} + path.gsub!(%r{/(\(+)/?}, '\1/') unless path =~ %r{^/(\(+[^)]+\)){1,}$} path end @@ -664,7 +676,6 @@ module ActionDispatch def define_generate_prefix(app, name) _route = @set.named_routes.get name _routes = @set - _url_helpers = @set.url_helpers script_namer = ->(options) do prefix_options = options.slice(*_route.segment_keys) @@ -676,7 +687,7 @@ module ActionDispatch # We must actually delete prefix segment keys to avoid passing them to next url_for. _route.segment_keys.each { |k| options.delete(k) } - _url_helpers.send("#{name}_path", prefix_options) + @set.url_helpers.send("#{name}_path", prefix_options) end app.routes.define_mounted_helper(name, script_namer) diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 07d3a41173..da4f285f61 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -245,7 +245,7 @@ module ActionDispatch missing_keys << missing_key } constraints = Hash[@route.requirements.merge(params).sort_by { |k, v| k.to_s }] - message = "No route matches #{constraints.inspect}".dup + message = +"No route matches #{constraints.inspect}" message << ", missing required keys: #{missing_keys.sort.inspect}" raise ActionController::UrlGenerationError, message @@ -378,6 +378,8 @@ module ActionDispatch @disable_clear_and_finalize = false @finalized = false @env_key = "ROUTES_#{object_id}_SCRIPT_NAME".freeze + @url_helpers = nil + @deferred_classes = [] @set = Journey::Routes.new @router = Journey::Router.new @set @@ -433,10 +435,34 @@ module ActionDispatch end private :eval_block + def include_helpers(klass, include_path_helpers) + if @finalized + include_helpers_now klass, include_path_helpers + else + @deferred_classes << [klass, include_path_helpers] + end + end + + def include_helpers_now(klass, include_path_helpers) + namespace = klass.parents.detect { |m| m.respond_to?(:railtie_include_helpers) } + + if namespace && namespace.railtie_namespace.routes != self + namespace.railtie_include_helpers(klass, include_path_helpers) + else + klass.include(url_helpers(include_path_helpers)) + end + end + private :include_helpers_now + def finalize! return if @finalized @append.each { |blk| eval_block(blk) } @finalized = true + @url_helpers = build_url_helper_module true + @deferred_classes.each { |klass, include_path_helpers| + include_helpers klass, include_path_helpers + } + @deferred_classes.clear end def clear! @@ -465,11 +491,10 @@ 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, helpers, script_namer) + RoutesProxy.new(routes, _routes_context, routes.url_helpers, script_namer) end end @@ -480,7 +505,20 @@ module ActionDispatch RUBY end + class UnfinalizedRouteSet < StandardError + end + def url_helpers(supports_path = true) + raise UnfinalizedRouteSet, "routes have not been finalized. Please call `finalize!` or use `draw(&block)`" unless @finalized + + if supports_path + @url_helpers + else + build_url_helper_module false + end + end + + def build_url_helper_module(supports_path) routes = self Module.new do |