aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/abstract_controller/railties/routes_helpers.rb7
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb3
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb42
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb37
-rw-r--r--actionpack/test/abstract_unit.rb5
-rw-r--r--actionpack/test/controller/integration_test.rb7
-rw-r--r--actionpack/test/dispatch/routing/ipv6_redirect_test.rb10
-rw-r--r--actionpack/test/dispatch/url_generation_test.rb9
-rw-r--r--railties/lib/rails/engine.rb16
-rw-r--r--railties/lib/rails/engine/configuration.rb2
10 files changed, 102 insertions, 36 deletions
diff --git a/actionpack/lib/abstract_controller/railties/routes_helpers.rb b/actionpack/lib/abstract_controller/railties/routes_helpers.rb
index b6e5631a4e..c97be074c8 100644
--- a/actionpack/lib/abstract_controller/railties/routes_helpers.rb
+++ b/actionpack/lib/abstract_controller/railties/routes_helpers.rb
@@ -7,11 +7,8 @@ module AbstractController
Module.new do
define_method(:inherited) do |klass|
super(klass)
- if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
- klass.include(namespace.railtie_routes_url_helpers(include_path_helpers))
- else
- klass.include(routes.url_helpers(include_path_helpers))
- end
+
+ routes.include_helpers klass, include_path_helpers
end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 3f7cf0950d..b618b9c400 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -664,7 +664,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 +675,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 acce8a7ef3..da4f285f61 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -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
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index af41521c5c..0e8712f8d9 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -138,6 +138,20 @@ module ActionDispatch
assert_generates(path.is_a?(Hash) ? path[:path] : path, generate_options, defaults, extras, message)
end
+ # Provides a hook on `finalize!` so we can mutate a controller after the
+ # route set has been drawn.
+ class WithRouting < ActionDispatch::Routing::RouteSet # :nodoc:
+ def initialize(&block)
+ super()
+ @block = block
+ end
+
+ def finalize!
+ super
+ @block.call self
+ end
+ end
+
# A helper to make it easier to test different route configurations.
# This method temporarily replaces @routes with a new RouteSet instance.
#
@@ -152,16 +166,19 @@ module ActionDispatch
# end
#
def with_routing
- old_routes, @routes = @routes, ActionDispatch::Routing::RouteSet.new
- if defined?(@controller) && @controller
- old_controller, @controller = @controller, @controller.clone
- _routes = @routes
-
- @controller.singleton_class.include(_routes.url_helpers)
-
- if @controller.respond_to? :view_context_class
- @controller.view_context_class = Class.new(@controller.view_context_class) do
- include _routes.url_helpers
+ old_routes = @routes
+ old_controller = nil
+ @routes = WithRouting.new do |_routes|
+ if defined?(@controller) && @controller
+ old_controller, @controller = @controller, @controller.clone
+ _routes = @routes
+
+ @controller.singleton_class.include(_routes.url_helpers)
+
+ if @controller.respond_to? :view_context_class
+ @controller.view_context_class = Class.new(@controller.view_context_class) do
+ include _routes.url_helpers
+ end
end
end
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 65dd28b3d7..7c9f15108d 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -100,7 +100,10 @@ end
class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
def self.build_app(routes = nil)
- RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
+ routes ||= ActionDispatch::Routing::RouteSet.new.tap { |rs|
+ rs.draw { }
+ }
+ RoutedRackApp.new(routes) do |middleware|
middleware.use ActionDispatch::ShowExceptions, ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public")
middleware.use ActionDispatch::DebugExceptions
middleware.use ActionDispatch::Callbacks
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 39ede1442a..b078e8ad9f 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -542,9 +542,6 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest
def with_test_route_set
with_routing do |set|
controller = ::IntegrationProcessTest::IntegrationController.clone
- controller.class_eval do
- include set.url_helpers
- end
set.draw do
get "moved" => redirect("/method")
@@ -555,6 +552,10 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest
end
end
+ controller.class_eval do
+ include set.url_helpers
+ end
+
singleton_class.include(set.url_helpers)
yield
diff --git a/actionpack/test/dispatch/routing/ipv6_redirect_test.rb b/actionpack/test/dispatch/routing/ipv6_redirect_test.rb
index 31559bffc7..fb423d2951 100644
--- a/actionpack/test/dispatch/routing/ipv6_redirect_test.rb
+++ b/actionpack/test/dispatch/routing/ipv6_redirect_test.rb
@@ -4,6 +4,11 @@ require "abstract_unit"
class IPv6IntegrationTest < ActionDispatch::IntegrationTest
Routes = ActionDispatch::Routing::RouteSet.new
+ Routes.draw do
+ get "/", to: "bad_route_request#index", as: :index
+ get "/foo", to: "bad_route_request#foo", as: :foo
+ end
+
include Routes.url_helpers
class ::BadRouteRequestController < ActionController::Base
@@ -17,11 +22,6 @@ class IPv6IntegrationTest < ActionDispatch::IntegrationTest
end
end
- Routes.draw do
- get "/", to: "bad_route_request#index", as: :index
- get "/foo", to: "bad_route_request#foo", as: :foo
- end
-
def _routes
Routes
end
diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb
index aef9351de1..b0096d26be 100644
--- a/actionpack/test/dispatch/url_generation_test.rb
+++ b/actionpack/test/dispatch/url_generation_test.rb
@@ -4,16 +4,13 @@ require "abstract_unit"
module TestUrlGeneration
class WithMountPoint < ActionDispatch::IntegrationTest
- Routes = ActionDispatch::Routing::RouteSet.new
- include Routes.url_helpers
-
class ::MyRouteGeneratingController < ActionController::Base
- include Routes.url_helpers
def index
render plain: foo_path
end
end
+ Routes = ActionDispatch::Routing::RouteSet.new
Routes.draw do
get "/foo", to: "my_route_generating#index", as: :foo
@@ -22,6 +19,10 @@ module TestUrlGeneration
mount MyRouteGeneratingController.action(:index), at: "/bar"
end
+ class ::MyRouteGeneratingController
+ include Routes.url_helpers
+ end
+
APP = build_app Routes
def _routes
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 6a13a84108..901934826b 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -403,6 +403,12 @@ module Rails
define_method(:railtie_helpers_paths) { railtie.helpers_paths }
end
+ unless mod.respond_to?(:railtie_include_helpers)
+ define_method(:railtie_include_helpers) { |klass, include_path_helpers|
+ railtie.routes.include_helpers(klass, include_path_helpers)
+ }
+ end
+
unless mod.respond_to?(:railtie_routes_url_helpers)
define_method(:railtie_routes_url_helpers) { |include_path_helpers = true| railtie.routes.url_helpers(include_path_helpers) }
end
@@ -473,9 +479,13 @@ module Rails
# files inside eager_load paths.
def eager_load!
config.eager_load_paths.each do |load_path|
- matcher = /\A#{Regexp.escape(load_path.to_s)}\/(.*)\.rb\Z/
- Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
- require_dependency file.sub(matcher, '\1')
+ if File.file?(load_path)
+ require_dependency load_path
+ else
+ matcher = /\A#{Regexp.escape(load_path.to_s)}\/(.*)\.rb\Z/
+ Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
+ require_dependency file.sub(matcher, '\1')
+ end
end
end
end
diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb
index 6bf0406b21..7595272c03 100644
--- a/railties/lib/rails/engine/configuration.rb
+++ b/railties/lib/rails/engine/configuration.rb
@@ -38,6 +38,7 @@ module Rails
@paths ||= begin
paths = Rails::Paths::Root.new(@root)
+ paths.add "config/routes.rb", eager_load: true
paths.add "app", eager_load: true, glob: "{*,*/concerns}"
paths.add "app/assets", glob: "*"
paths.add "app/controllers", eager_load: true
@@ -55,7 +56,6 @@ module Rails
paths.add "config/environments", glob: "#{Rails.env}.rb"
paths.add "config/initializers", glob: "**/*.rb"
paths.add "config/locales", glob: "*.{rb,yml}"
- paths.add "config/routes.rb"
paths.add "db"
paths.add "db/migrate"