Skip to content

Commit e97db3b

Browse files
authored
Merge pull request rails#51614 from gmcgibbon/defer_route_drawing
Defer route drawing to the first request, or when url_helpers called
2 parents a27a175 + e54f869 commit e97db3b

File tree

21 files changed

+283
-11
lines changed

21 files changed

+283
-11
lines changed

actionpack/lib/action_dispatch/testing/assertions/routing.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ def with_routing(&block)
4646
def create_routes
4747
app = self.app
4848
routes = ActionDispatch::Routing::RouteSet.new
49-
rack_app = app.config.middleware.build(routes)
49+
middleware = app.config.middleware.dup
50+
middleware.delete(Rails::Rack::LoadRoutes) if defined?(Rails::Rack::LoadRoutes)
51+
rack_app = middleware.build(routes)
5052
https = integration_session.https?
5153
host = integration_session.host
5254

actionpack/test/dispatch/routing_assertions_test.rb

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
require "rails/engine"
55
require "controller/fake_controllers"
66

7-
class SecureArticlesController < ArticlesController; end
7+
class SecureArticlesController < ArticlesController
8+
def index
9+
render(inline: "")
10+
end
11+
end
812
class BlockArticlesController < ArticlesController; end
913
class QueryArticlesController < ArticlesController; end
1014

@@ -276,6 +280,20 @@ class RoutingAssertionsControllerTest < ActionController::TestCase
276280

277281
class WithRoutingTest < ActionController::TestCase
278282
include RoutingAssertionsSharedTests::WithRoutingSharedTests
283+
284+
test "with_routing routes are reachable" do
285+
@controller = SecureArticlesController.new
286+
287+
with_routing do |routes|
288+
routes.draw do
289+
get :new_route, to: "secure_articles#index"
290+
end
291+
292+
get :index
293+
294+
assert_predicate(response, :ok?)
295+
end
296+
end
279297
end
280298
end
281299

@@ -295,6 +313,18 @@ class RoutingAssertionsIntegrationTest < ActionDispatch::IntegrationTest
295313

296314
class WithRoutingTest < ActionDispatch::IntegrationTest
297315
include RoutingAssertionsSharedTests::WithRoutingSharedTests
316+
317+
test "with_routing routes are reachable" do
318+
with_routing do |routes|
319+
routes.draw do
320+
get :new_route, to: "secure_articles#index"
321+
end
322+
323+
get "/new_route"
324+
325+
assert_predicate(response, :ok?)
326+
end
327+
end
298328
end
299329

300330
class WithRoutingSettingsTest < ActionDispatch::IntegrationTest

railties/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
* Defer route drawing to the first request, or when url_helpers are called
2+
3+
Executes the first routes reload in middleware, or when a route set's
4+
url_helpers receives a route call / asked if it responds to a route.
5+
Previously, this was executed unconditionally on boot, which can
6+
slow down boot time unnecessarily for larger apps with lots of routes.
7+
8+
*Gannon McGibbon*
9+
110
* Add options to bin/rails app:update.
211

312
`bin/rails app:update` now supports the same generic options that generators do:

railties/lib/rails/application.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
require "active_support/encrypted_configuration"
1010
require "active_support/hash_with_indifferent_access"
1111
require "active_support/configuration_file"
12+
require "active_support/parameter_filter"
1213
require "rails/engine"
1314
require "rails/autoloaders"
1415

railties/lib/rails/application/default_middleware_stack.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ def build_stack
6262
middleware.use ::ActionDispatch::ActionableExceptions
6363
end
6464

65+
middleware.use ::Rails::Rack::LoadRoutes, app.routes_reloader unless app.config.eager_load
66+
6567
if config.reloading_enabled?
6668
middleware.use ::ActionDispatch::Reloader, app.reloader
6769
end

railties/lib/rails/application/finisher.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ def self.complete(_state)
159159
initializer :set_routes_reloader_hook do |app|
160160
reloader = routes_reloader
161161
reloader.eager_load = app.config.eager_load
162-
reloader.execute
163162
reloaders << reloader
164163

165164
app.reloader.to_run do
@@ -177,7 +176,12 @@ def self.complete(_state)
177176
ActiveSupport.run_load_hooks(:after_routes_loaded, self)
178177
end
179178

180-
ActiveSupport.run_load_hooks(:after_routes_loaded, self)
179+
if reloader.eager_load
180+
reloader.execute
181+
ActiveSupport.run_load_hooks(:after_routes_loaded, self)
182+
elsif reloader.loaded
183+
ActiveSupport.run_load_hooks(:after_routes_loaded, self)
184+
end
181185
end
182186

183187
# Set clearing dependencies after the finisher hook to ensure paths

railties/lib/rails/application/routes_reloader.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class Application
77
class RoutesReloader
88
include ActiveSupport::Callbacks
99

10-
attr_reader :route_sets, :paths, :external_routes
10+
attr_reader :route_sets, :paths, :external_routes, :loaded
1111
attr_accessor :eager_load
1212
attr_writer :run_after_load_paths # :nodoc:
1313
delegate :execute_if_updated, :execute, :updated?, to: :updater
@@ -17,9 +17,11 @@ def initialize
1717
@route_sets = []
1818
@external_routes = []
1919
@eager_load = false
20+
@loaded = false
2021
end
2122

2223
def reload!
24+
@loaded = true
2325
clear!
2426
load_paths
2527
finalize!
@@ -28,6 +30,13 @@ def reload!
2830
revert
2931
end
3032

33+
def execute_unless_loaded
34+
unless @loaded
35+
execute
36+
true
37+
end
38+
end
39+
3140
private
3241
def updater
3342
@updater ||= begin

railties/lib/rails/commands/routes/routes_command.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def invoke_command(*)
2323
desc "routes", "List all the defined routes"
2424
def perform(*)
2525
boot_application!
26+
Rails.application.routes_reloader.execute_unless_loaded
2627
require "action_dispatch/routing/inspector"
2728

2829
say inspector.format(formatter, routes_filter)

railties/lib/rails/commands/unused_routes/unused_routes_command.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def action_missing?
4141

4242
def perform(*)
4343
boot_application!
44+
Rails.application.routes_reloader.execute_unless_loaded
4445
require "action_dispatch/routing/inspector"
4546

4647
say(inspector.format(formatter, routes_filter))

railties/lib/rails/engine.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ module Rails
349349
# config.railties_order = [Blog::Engine, :main_app, :all]
350350
class Engine < Railtie
351351
autoload :Configuration, "rails/engine/configuration"
352+
autoload :RouteSet, "rails/engine/route_set"
352353

353354
class << self
354355
attr_accessor :called_from, :isolated
@@ -543,7 +544,7 @@ def env_config
543544
# Defines the routes for this engine. If a block is given to
544545
# routes, it is appended to the engine.
545546
def routes(&block)
546-
@routes ||= ActionDispatch::Routing::RouteSet.new_with_config(config)
547+
@routes ||= RouteSet.new_with_config(config)
547548
@routes.append(&block) if block_given?
548549
@routes
549550
end

0 commit comments

Comments
 (0)