railties 7.2.3 → 8.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +168 -256
  3. data/lib/minitest/rails_plugin.rb +8 -1
  4. data/lib/rails/application/bootstrap.rb +0 -1
  5. data/lib/rails/application/configuration.rb +17 -14
  6. data/lib/rails/application/default_middleware_stack.rb +4 -0
  7. data/lib/rails/application/finisher.rb +2 -3
  8. data/lib/rails/application/routes_reloader.rb +17 -3
  9. data/lib/rails/application.rb +10 -1
  10. data/lib/rails/application_controller.rb +2 -0
  11. data/lib/rails/backtrace_cleaner.rb +2 -2
  12. data/lib/rails/code_statistics.rb +128 -86
  13. data/lib/rails/code_statistics_calculator.rb +78 -76
  14. data/lib/rails/command/helpers/editor.rb +1 -1
  15. data/lib/rails/command.rb +0 -6
  16. data/lib/rails/commands/app/update_command.rb +5 -9
  17. data/lib/rails/commands/console/irb_console.rb +3 -6
  18. data/lib/rails/commands/credentials/USAGE +4 -4
  19. data/lib/rails/commands/credentials/credentials_command.rb +5 -1
  20. data/lib/rails/commands/dev/dev_command.rb +1 -1
  21. data/lib/rails/commands/devcontainer/devcontainer_command.rb +2 -1
  22. data/lib/rails/commands/stats/stats_command.rb +19 -0
  23. data/lib/rails/console/methods.rb +5 -21
  24. data/lib/rails/dev_caching.rb +2 -2
  25. data/lib/rails/engine/configuration.rb +3 -1
  26. data/lib/rails/engine/lazy_route_set.rb +111 -0
  27. data/lib/rails/engine.rb +10 -6
  28. data/lib/rails/gem_version.rb +3 -3
  29. data/lib/rails/generators/actions.rb +3 -3
  30. data/lib/rails/generators/app_base.rb +76 -56
  31. data/lib/rails/generators/base.rb +0 -4
  32. data/lib/rails/generators/bundle_helper.rb +34 -0
  33. data/lib/rails/generators/database.rb +101 -67
  34. data/lib/rails/generators/erb/authentication/authentication_generator.rb +15 -0
  35. data/lib/rails/generators/erb/authentication/templates/app/views/passwords/edit.html.erb +9 -0
  36. data/lib/rails/generators/erb/authentication/templates/app/views/passwords/new.html.erb +8 -0
  37. data/lib/rails/generators/erb/authentication/templates/app/views/sessions/new.html.erb +11 -0
  38. data/lib/rails/generators/generated_attribute.rb +16 -11
  39. data/lib/rails/generators/rails/app/app_generator.rb +30 -30
  40. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +23 -6
  41. data/lib/rails/generators/rails/app/templates/Gemfile.tt +27 -12
  42. data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css.tt +6 -11
  43. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +10 -3
  44. data/lib/rails/generators/rails/app/templates/bin/dev.tt +1 -0
  45. data/lib/rails/generators/rails/app/templates/bin/setup.tt +5 -8
  46. data/lib/rails/generators/rails/app/templates/bin/thrust.tt +4 -0
  47. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +24 -1
  48. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +23 -0
  49. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +50 -0
  50. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +30 -5
  51. data/lib/rails/generators/rails/app/templates/config/deploy.yml.tt +128 -0
  52. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +12 -23
  53. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +31 -51
  54. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +5 -19
  55. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +0 -7
  56. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +1 -1
  57. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_0.rb.tt +30 -0
  58. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +11 -2
  59. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +3 -3
  60. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +4 -3
  61. data/lib/rails/generators/rails/app/templates/dockerignore.tt +7 -2
  62. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +12 -6
  63. data/lib/rails/generators/rails/app/templates/gitignore.tt +1 -2
  64. data/lib/rails/generators/rails/app/templates/kamal-secrets.tt +17 -0
  65. data/lib/rails/generators/rails/app/templates/public/400.html +114 -0
  66. data/lib/rails/generators/rails/app/templates/public/404.html +113 -66
  67. data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +113 -65
  68. data/lib/rails/generators/rails/app/templates/public/422.html +113 -66
  69. data/lib/rails/generators/rails/app/templates/public/500.html +113 -65
  70. data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
  71. data/lib/rails/generators/rails/app/templates/public/icon.svg +2 -2
  72. data/lib/rails/generators/rails/app/templates/ruby-version.tt +1 -1
  73. data/lib/rails/generators/rails/authentication/USAGE +6 -0
  74. data/lib/rails/generators/rails/authentication/authentication_generator.rb +60 -0
  75. data/lib/rails/generators/rails/authentication/templates/app/channels/application_cable/connection.rb.tt +16 -0
  76. data/lib/rails/generators/rails/authentication/templates/app/controllers/concerns/authentication.rb.tt +52 -0
  77. data/lib/rails/generators/rails/authentication/templates/app/controllers/passwords_controller.rb.tt +33 -0
  78. data/lib/rails/generators/rails/authentication/templates/app/controllers/sessions_controller.rb.tt +21 -0
  79. data/lib/rails/generators/rails/authentication/templates/app/mailers/passwords_mailer.rb.tt +6 -0
  80. data/lib/rails/generators/rails/authentication/templates/app/models/current.rb.tt +4 -0
  81. data/lib/rails/generators/rails/authentication/templates/app/models/session.rb.tt +3 -0
  82. data/lib/rails/generators/rails/authentication/templates/app/models/user.rb.tt +6 -0
  83. data/lib/rails/generators/rails/authentication/templates/app/views/passwords_mailer/reset.html.erb.tt +4 -0
  84. data/lib/rails/generators/rails/authentication/templates/app/views/passwords_mailer/reset.text.erb.tt +2 -0
  85. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +4 -0
  86. data/lib/rails/generators/rails/db/system/change/change_generator.rb +1 -1
  87. data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +12 -2
  88. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +1 -1
  89. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +5 -5
  90. data/lib/rails/generators/rails/plugin/plugin_generator.rb +7 -9
  91. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +1 -1
  92. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +3 -3
  93. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +2 -2
  94. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +3 -3
  95. data/lib/rails/generators/rails/script/USAGE +18 -0
  96. data/lib/rails/generators/rails/script/script_generator.rb +18 -0
  97. data/lib/rails/generators/rails/script/templates/script.rb.tt +3 -0
  98. data/lib/rails/generators/test_unit/authentication/authentication_generator.rb +18 -0
  99. data/lib/rails/generators/test_unit/authentication/templates/test/fixtures/users.yml.tt +9 -0
  100. data/lib/rails/generators/test_unit/authentication/templates/test/mailers/previews/passwords_mailer_preview.rb.tt +7 -0
  101. data/lib/rails/generators/test_unit/authentication/templates/test/models/user_test.rb.tt +7 -0
  102. data/lib/rails/generators.rb +1 -0
  103. data/lib/rails/health_controller.rb +2 -0
  104. data/lib/rails/info.rb +2 -1
  105. data/lib/rails/info_controller.rb +10 -4
  106. data/lib/rails/rack/silence_request.rb +33 -0
  107. data/lib/rails/rack.rb +1 -0
  108. data/lib/rails/source_annotation_extractor.rb +37 -16
  109. data/lib/rails/tasks/statistics.rake +13 -28
  110. data/lib/rails/templates/rails/info/notes.html.erb +65 -0
  111. data/lib/rails/templates/rails/mailers/email.html.erb +1 -1
  112. data/lib/rails/test_unit/line_filtering.rb +24 -3
  113. data/lib/rails/test_unit/reporter.rb +8 -4
  114. data/lib/rails/test_unit/runner.rb +1 -0
  115. metadata +46 -37
  116. data/lib/rails/console/app.rb +0 -8
  117. data/lib/rails/console/helpers.rb +0 -8
  118. data/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt +0 -2
  119. data/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb.tt +0 -4
  120. data/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb.tt +0 -4
  121. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +0 -70
  122. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +0 -13
  123. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +0 -13
  124. data/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js.tt +0 -10
  125. data/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js.tt +0 -6
  126. data/lib/rails/generators/rails/plugin/templates/rails/javascripts.js.tt +0 -17
@@ -12,6 +12,9 @@ module Rails
12
12
 
13
13
  desc "update", "Update configs and some other initially generated files (or use just update:configs or update:bin)"
14
14
  def perform
15
+ require_application!
16
+ Rails.application.deprecators.silenced = true
17
+
15
18
  configs
16
19
  bin
17
20
  public_directory
@@ -71,23 +74,16 @@ module Rails
71
74
  skip_action_cable: !defined?(ActionCable::Engine),
72
75
  skip_brakeman: skip_gem?("brakeman"),
73
76
  skip_rubocop: skip_gem?("rubocop"),
77
+ skip_thruster: skip_gem?("thruster"),
74
78
  skip_test: !defined?(Rails::TestUnitRailtie),
75
79
  skip_system_test: Rails.application.config.generators.system_tests.nil?,
76
- asset_pipeline: asset_pipeline,
77
80
  skip_asset_pipeline: asset_pipeline.nil?,
78
81
  skip_bootsnap: !defined?(Bootsnap),
79
82
  }.merge(options)
80
83
  end
81
84
 
82
85
  def asset_pipeline
83
- case
84
- when defined?(Sprockets::Railtie)
85
- "sprockets"
86
- when defined?(Propshaft::Railtie)
87
- "propshaft"
88
- else
89
- nil
90
- end
86
+ "propshaft" if defined?(Propshaft::Railtie)
91
87
  end
92
88
 
93
89
  def skip_gem?(gem_name)
@@ -6,7 +6,6 @@ require "irb/command"
6
6
  module Rails
7
7
  class Console
8
8
  class RailsHelperBase < IRB::HelperMethod::Base
9
- include ConsoleMethods
10
9
  end
11
10
 
12
11
  class ControllerHelper < RailsHelperBase
@@ -32,6 +31,7 @@ module Rails
32
31
 
33
32
  def execute(*)
34
33
  app = Rails.application
34
+ app.reload_routes_unless_loaded
35
35
  session = ActionDispatch::Integration::Session.new(app)
36
36
 
37
37
  # This makes app.url_for and app.foo_path available in the console
@@ -87,7 +87,8 @@ module Rails
87
87
 
88
88
  env = colorized_env
89
89
  prompt_prefix = "%N(#{env})"
90
- IRB.conf[:IRB_NAME] = @app.name
90
+ # Respect user's configured irb name.
91
+ IRB.conf[:IRB_NAME] = @app.name if IRB.conf[:IRB_NAME] == "irb"
91
92
 
92
93
  IRB.conf[:PROMPT][:RAILS_PROMPT] = {
93
94
  PROMPT_I: "#{prompt_prefix}> ",
@@ -107,10 +108,6 @@ module Rails
107
108
  end
108
109
  end
109
110
 
110
- # Because some users/libs use Rails::ConsoleMethods to extend Rails console,
111
- # we still include it for backward compatibility.
112
- IRB::ExtendCommandBundle.include ConsoleMethods
113
-
114
111
  # Respect user's choice of prompt mode.
115
112
  IRB.conf[:PROMPT_MODE] = :RAILS_PROMPT if IRB.conf[:PROMPT_MODE] == :DEFAULT
116
113
  IRB::Irb.new.run(IRB.conf)
@@ -38,8 +38,8 @@ Set up Git to Diff Credentials:
38
38
  Running the command enrolls the project such that all credentials files use the
39
39
  "rails_credentials" diff driver in .gitattributes.
40
40
 
41
- Additionally since Git requires the driver itself to be set up in a config file
42
- that isn't tracked Rails automatically ensures it's configured when running
41
+ Additionally, since Git requires the driver itself to be set up in a config file
42
+ that isn't tracked, Rails automatically ensures it's configured when running
43
43
  `<%= executable(:edit) %>`.
44
44
 
45
45
  Otherwise each co-worker would have to run enable manually, including on each new
@@ -48,8 +48,8 @@ Set up Git to Diff Credentials:
48
48
  To disenroll from this feature, run `<%= executable(:diff) %> --disenroll`.
49
49
 
50
50
  Editing Credentials:
51
- This will open a temporary file in `$VISUAL` or `$EDITOR` with the decrypted
52
- contents to edit the encrypted credentials.
51
+ `<%= executable(:edit) %>` will open a temporary file in `$VISUAL` or `$EDITOR`
52
+ with the decrypted contents to edit the encrypted credentials.
53
53
 
54
54
  When the temporary file is next saved the contents are encrypted and written to
55
55
  `config/credentials.yml.enc` while the file itself is destroyed to prevent credentials
@@ -128,7 +128,11 @@ module Rails
128
128
  end
129
129
 
130
130
  def extract_environment_from_path(path)
131
- available_environments.find { |env| path.end_with?("#{env}.yml.enc") }
131
+ available_environments.find { |env| path.end_with?("#{env}.yml.enc") } || extract_custom_environment(path)
132
+ end
133
+
134
+ def extract_custom_environment(path)
135
+ path =~ %r{config/credentials/(.+)\.yml\.enc} && $1
132
136
  end
133
137
  end
134
138
  end
@@ -5,7 +5,7 @@ require "rails/dev_caching"
5
5
  module Rails
6
6
  module Command
7
7
  class DevCommand < Base # :nodoc:
8
- desc "cache", "Toggle development mode caching on/off"
8
+ desc "cache", "Toggle Action Controller development mode caching on/off"
9
9
  def cache
10
10
  Rails::DevCaching.enable_by_file
11
11
  end
@@ -24,9 +24,10 @@ module Rails
24
24
  app_name: Rails.application.railtie_name.chomp("_application"),
25
25
  database: !!defined?(ActiveRecord) && database,
26
26
  active_storage: !!defined?(ActiveStorage),
27
- redis: !!(defined?(ActionCable) || defined?(ActiveJob)),
27
+ redis: !!((defined?(ActionCable) && !defined?(SolidCable)) || (defined?(ActiveJob) && !defined?(SolidQueue))),
28
28
  system_test: File.exist?("test/application_system_test_case.rb"),
29
29
  node: File.exist?(".node-version"),
30
+ kamal: File.exist?("config/deploy.yml"),
30
31
  }
31
32
  end
32
33
 
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module Command
5
+ class StatsCommand < Base # :nodoc:
6
+ desc "stats", "Report code statistics (KLOCs, etc) from the application or engine"
7
+ def perform
8
+ require "rails/code_statistics"
9
+ boot_application!
10
+
11
+ stat_directories = Rails::CodeStatistics.directories.map do |name, dir|
12
+ [name, Rails::Command.application_root.join(dir)]
13
+ end.select { |name, dir| File.directory?(dir) }
14
+
15
+ Rails::CodeStatistics.new(*stat_directories).to_s
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,23 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Rails
4
- module ConsoleMethods
5
- def self.include(_mod, ...)
6
- raise_deprecation_warning
7
- super
8
- end
9
-
10
- def self.method_added(_method_name)
11
- raise_deprecation_warning
12
- super
13
- end
14
-
15
- def self.raise_deprecation_warning
16
- Rails.deprecator.warn(<<~MSG, caller_locations(2..2))
17
- Extending Rails console through `Rails::ConsoleMethods` is deprecated and will be removed in Rails 8.0.
18
- Please directly use IRB's extension API to add new commands or helpers to the console.
19
- For more details, please visit: https://github.com/ruby/irb/blob/master/EXTEND_IRB.md
20
- MSG
21
- end
22
- end
23
- end
3
+ Rails.deprecator.warn(<<~MSG, caller_locations(0..1))
4
+ `rails/console/methods` has been deprecated and will be removed in Rails 8.1.
5
+ Please directly use IRB's extension API to add new commands or helpers to the console.
6
+ For more details, please visit: https://github.com/ruby/irb/blob/master/EXTEND_IRB.md
7
+ MSG
@@ -12,10 +12,10 @@ module Rails
12
12
 
13
13
  if File.exist?(FILE)
14
14
  delete_cache_file
15
- puts "Development mode is no longer being cached."
15
+ puts "Action Controller caching disabled for development mode."
16
16
  else
17
17
  create_cache_file
18
- puts "Development mode is now being cached."
18
+ puts "Action Controller caching enabled for development mode."
19
19
  end
20
20
 
21
21
  FileUtils.touch "tmp/restart.txt"
@@ -6,7 +6,7 @@ module Rails
6
6
  class Engine
7
7
  class Configuration < ::Rails::Railtie::Configuration
8
8
  attr_reader :root
9
- attr_accessor :middleware, :javascript_path
9
+ attr_accessor :middleware, :javascript_path, :route_set_class, :default_scope
10
10
  attr_writer :eager_load_paths, :autoload_once_paths, :autoload_paths
11
11
 
12
12
  # An array of custom autoload paths to be added to the ones defined
@@ -44,6 +44,8 @@ module Rails
44
44
  @generators = app_generators.dup
45
45
  @middleware = Rails::Configuration::MiddlewareStackProxy.new
46
46
  @javascript_path = "javascript"
47
+ @route_set_class = ActionDispatch::Routing::RouteSet
48
+ @default_scope = nil
47
49
 
48
50
  @autoload_paths = []
49
51
  @autoload_once_paths = []
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "action_dispatch/routing/route_set"
6
+
7
+ # :enddoc:
8
+
9
+ module Rails
10
+ class Engine
11
+ class LazyRouteSet < ActionDispatch::Routing::RouteSet
12
+ class NamedRouteCollection < ActionDispatch::Routing::RouteSet::NamedRouteCollection
13
+ def route_defined?(name)
14
+ Rails.application&.reload_routes_unless_loaded
15
+ super
16
+ end
17
+ end
18
+
19
+ module ProxyUrlHelpers
20
+ def url_for(options)
21
+ Rails.application&.reload_routes_unless_loaded
22
+ super
23
+ end
24
+
25
+ def full_url_for(options)
26
+ Rails.application&.reload_routes_unless_loaded
27
+ super
28
+ end
29
+
30
+ def route_for(name, *args)
31
+ Rails.application&.reload_routes_unless_loaded
32
+ super
33
+ end
34
+
35
+ def optimize_routes_generation?
36
+ Rails.application&.reload_routes_unless_loaded
37
+ super
38
+ end
39
+ end
40
+
41
+ def initialize(config = DEFAULT_CONFIG)
42
+ super
43
+ self.named_routes = NamedRouteCollection.new
44
+ named_routes.url_helpers_module.prepend(method_missing_module)
45
+ named_routes.path_helpers_module.prepend(method_missing_module)
46
+ end
47
+
48
+ def generate_extras(options, recall = {})
49
+ Rails.application&.reload_routes_unless_loaded
50
+
51
+ super(options, recall)
52
+ end
53
+
54
+ def generate_url_helpers(supports_path)
55
+ super.tap { |mod| mod.singleton_class.prepend(ProxyUrlHelpers) }
56
+ end
57
+
58
+ def call(req)
59
+ Rails.application&.reload_routes_unless_loaded
60
+ super
61
+ end
62
+
63
+ def polymorphic_mappings
64
+ Rails.application&.reload_routes_unless_loaded
65
+ super
66
+ end
67
+
68
+ def draw(&block)
69
+ Rails.application&.reload_routes_unless_loaded
70
+ super
71
+ end
72
+
73
+ def recognize_path(path, environment = {})
74
+ Rails.application&.reload_routes_unless_loaded
75
+ super
76
+ end
77
+
78
+ def recognize_path_with_request(...)
79
+ Rails.application&.reload_routes_unless_loaded
80
+ super
81
+ end
82
+
83
+ def routes
84
+ Rails.application&.reload_routes_unless_loaded
85
+ super
86
+ end
87
+
88
+ private
89
+ def method_missing_module
90
+ @method_missing_module ||= Module.new do
91
+ private
92
+ def method_missing(...)
93
+ if Rails.application&.reload_routes_unless_loaded
94
+ public_send(...)
95
+ else
96
+ super
97
+ end
98
+ end
99
+
100
+ def respond_to_missing?(...)
101
+ if Rails.application&.reload_routes_unless_loaded
102
+ respond_to?(...)
103
+ else
104
+ super
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
data/lib/rails/engine.rb CHANGED
@@ -6,7 +6,6 @@ require "active_support/callbacks"
6
6
  require "active_support/core_ext/module/delegation"
7
7
  require "active_support/core_ext/object/try"
8
8
  require "pathname"
9
- require "thread"
10
9
 
11
10
  module Rails
12
11
  # +Rails::Engine+ allows you to wrap a specific \Rails application or subset of
@@ -246,7 +245,7 @@ module Rails
246
245
  # polymorphic_url(MyEngine::Article.new)
247
246
  # # => "articles_path" # not "my_engine_articles_path"
248
247
  #
249
- # form_for(MyEngine::Article.new) do
248
+ # form_with(model: MyEngine::Article.new) do
250
249
  # text_field :title # => <input type="text" name="article[title]" id="article_title" />
251
250
  # end
252
251
  #
@@ -295,7 +294,7 @@ module Rails
295
294
  # All you need to do is pass the helper as the first element in array with
296
295
  # attributes for URL:
297
296
  #
298
- # form_for([my_engine, @user])
297
+ # form_with(model: [my_engine, @user])
299
298
  #
300
299
  # This code will use <tt>my_engine.user_path(@user)</tt> to generate the proper route.
301
300
  #
@@ -349,6 +348,7 @@ module Rails
349
348
  # config.railties_order = [Blog::Engine, :main_app, :all]
350
349
  class Engine < Railtie
351
350
  autoload :Configuration, "rails/engine/configuration"
351
+ autoload :LazyRouteSet, "rails/engine/lazy_route_set"
352
352
 
353
353
  class << self
354
354
  attr_accessor :called_from, :isolated
@@ -385,7 +385,8 @@ module Rails
385
385
  def isolate_namespace(mod)
386
386
  engine_name(generate_railtie_name(mod.name))
387
387
 
388
- routes.default_scope = { module: ActiveSupport::Inflector.underscore(mod.name) }
388
+ config.default_scope = { module: ActiveSupport::Inflector.underscore(mod.name) }
389
+
389
390
  self.isolated = true
390
391
 
391
392
  unless mod.respond_to?(:railtie_namespace)
@@ -451,7 +452,6 @@ module Rails
451
452
  # Load console and invoke the registered hooks.
452
453
  # Check Rails::Railtie.console for more info.
453
454
  def load_console(app = self)
454
- require "rails/console/methods"
455
455
  run_console_blocks(app)
456
456
  self
457
457
  end
@@ -543,7 +543,7 @@ module Rails
543
543
  # Defines the routes for this engine. If a block is given to
544
544
  # routes, it is appended to the engine.
545
545
  def routes(&block)
546
- @routes ||= ActionDispatch::Routing::RouteSet.new_with_config(config)
546
+ @routes ||= config.route_set_class.new_with_config(config)
547
547
  @routes.append(&block) if block_given?
548
548
  @routes
549
549
  end
@@ -588,6 +588,10 @@ module Rails
588
588
  config.eager_load_paths.freeze
589
589
  end
590
590
 
591
+ initializer :make_routes_lazy, before: :bootstrap_hook do |app|
592
+ config.route_set_class = LazyRouteSet if Rails.env.local?
593
+ end
594
+
591
595
  initializer :add_routing_paths do |app|
592
596
  routing_paths = paths["config/routes.rb"].existent
593
597
  external_paths = self.paths["config/routes"].paths
@@ -7,9 +7,9 @@ module Rails
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 7
11
- MINOR = 2
12
- TINY = 3
10
+ MAJOR = 8
11
+ MINOR = 0
12
+ TINY = 5
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -520,9 +520,9 @@ module Rails
520
520
 
521
521
  def route_namespace_pattern(namespace)
522
522
  namespace.each_with_index.reverse_each.reduce(nil) do |pattern, (name, i)|
523
- cummulative_margin = "\\#{i + 1}[ ]{2}"
524
- blank_or_indented_line = "^[ ]*\n|^#{cummulative_margin}.*\n"
525
- "(?:(?:#{blank_or_indented_line})*?^(#{cummulative_margin})namespace :#{name} do\n#{pattern})?"
523
+ cumulative_margin = "\\#{i + 1}[ ]{2}"
524
+ blank_or_indented_line = "^[ ]*\n|^#{cumulative_margin}.*\n"
525
+ "(?:(?:#{blank_or_indented_line})*?^(#{cumulative_margin})namespace :#{name} do\n#{pattern})?"
526
526
  end.then do |pattern|
527
527
  /^([ ]*).+\.routes\.draw do[ ]*\n#{pattern}/
528
528
  end
@@ -7,19 +7,20 @@ require "open-uri"
7
7
  require "tsort"
8
8
  require "uri"
9
9
  require "rails/generators"
10
+ require "rails/generators/bundle_helper"
10
11
  require "active_support/core_ext/array/extract_options"
11
12
 
12
13
  module Rails
13
14
  module Generators
14
15
  class AppBase < Base # :nodoc:
15
16
  include AppName
17
+ include BundleHelper
16
18
 
17
19
  NODE_LTS_VERSION = "20.11.1"
18
20
  BUN_VERSION = "1.0.1"
19
21
 
20
22
  JAVASCRIPT_OPTIONS = %w( importmap bun webpack esbuild rollup )
21
23
  CSS_OPTIONS = %w( tailwind bootstrap bulma postcss sass )
22
- ASSET_PIPELINE_OPTIONS = %w( none sprockets propshaft )
23
24
 
24
25
  attr_accessor :rails_template
25
26
  add_shebang_option!
@@ -74,10 +75,6 @@ module Rails
74
75
 
75
76
  class_option :skip_asset_pipeline, type: :boolean, aliases: "-A", default: nil
76
77
 
77
- class_option :asset_pipeline, type: :string, aliases: "-a", default: "sprockets",
78
- enum: ASSET_PIPELINE_OPTIONS,
79
- desc: "Choose your asset pipeline"
80
-
81
78
  class_option :skip_javascript, type: :boolean, aliases: ["-J", "--skip-js"], default: (true if name == "plugin"),
82
79
  desc: "Skip JavaScript files"
83
80
 
@@ -99,6 +96,9 @@ module Rails
99
96
  class_option :skip_dev_gems, type: :boolean, default: nil,
100
97
  desc: "Skip development gems (e.g., web-console)"
101
98
 
99
+ class_option :skip_thruster, type: :boolean, default: nil,
100
+ desc: "Skip Thruster setup"
101
+
102
102
  class_option :skip_rubocop, type: :boolean, default: nil,
103
103
  desc: "Skip RuboCop setup"
104
104
 
@@ -108,10 +108,16 @@ module Rails
108
108
  class_option :skip_ci, type: :boolean, default: nil,
109
109
  desc: "Skip GitHub CI files"
110
110
 
111
+ class_option :skip_kamal, type: :boolean, default: nil,
112
+ desc: "Skip Kamal setup"
113
+
114
+ class_option :skip_solid, type: :boolean, default: nil,
115
+ desc: "Skip Solid Cache, Queue, and Cable setup"
116
+
111
117
  class_option :dev, type: :boolean, default: nil,
112
118
  desc: "Set up the #{name} with Gemfile pointing to your Rails checkout"
113
119
 
114
- class_option :devcontainer, type: :boolean, default: false,
120
+ class_option :devcontainer, type: :boolean, default: nil,
115
121
  desc: "Generate devcontainer files"
116
122
 
117
123
  class_option :edge, type: :boolean, default: nil,
@@ -197,7 +203,7 @@ module Rails
197
203
 
198
204
  OPTION_IMPLICATIONS = { # :nodoc:
199
205
  skip_active_job: [:skip_action_mailer, :skip_active_storage],
200
- skip_active_record: [:skip_active_storage],
206
+ skip_active_record: [:skip_active_storage, :skip_solid],
201
207
  skip_active_storage: [:skip_action_mailbox, :skip_action_text],
202
208
  skip_javascript: [:skip_hotwire],
203
209
  }
@@ -287,12 +293,7 @@ module Rails
287
293
  end
288
294
 
289
295
  def asset_pipeline_gemfile_entry
290
- return if skip_asset_pipeline?
291
-
292
- if options[:asset_pipeline] == "sprockets"
293
- GemfileEntry.floats "sprockets-rails",
294
- "The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]"
295
- elsif options[:asset_pipeline] == "propshaft"
296
+ unless skip_asset_pipeline?
296
297
  GemfileEntry.floats "propshaft", "The modern asset pipeline for Rails [https://github.com/rails/propshaft]"
297
298
  end
298
299
  end
@@ -386,12 +387,8 @@ module Rails
386
387
  options[:skip_asset_pipeline]
387
388
  end
388
389
 
389
- def skip_sprockets?
390
- skip_asset_pipeline? || options[:asset_pipeline] != "sprockets"
391
- end
392
-
393
- def skip_propshaft?
394
- skip_asset_pipeline? || options[:asset_pipeline] != "propshaft"
390
+ def skip_thruster?
391
+ options[:skip_thruster]
395
392
  end
396
393
 
397
394
  def skip_rubocop?
@@ -414,6 +411,14 @@ module Rails
414
411
  options[:devcontainer]
415
412
  end
416
413
 
414
+ def skip_kamal?
415
+ options[:skip_kamal]
416
+ end
417
+
418
+ def skip_solid?
419
+ options[:skip_solid]
420
+ end
421
+
417
422
  class GemfileEntry < Struct.new(:name, :version, :comment, :options, :commented_out)
418
423
  def initialize(name, version, comment, options = {}, commented_out = false)
419
424
  super
@@ -536,6 +541,11 @@ module Rails
536
541
  "latest"
537
542
  end
538
543
 
544
+ def yarn_through_corepack?
545
+ true if dockerfile_yarn_version == "latest"
546
+ dockerfile_yarn_version >= "2"
547
+ end
548
+
539
549
  def dockerfile_bun_version
540
550
  using_bun? and `bun --version`[/\d+\.\d+\.\d+/]
541
551
  rescue
@@ -572,7 +582,7 @@ module Rails
572
582
  end
573
583
 
574
584
  def dockerfile_base_packages
575
- # Add curl to work with the default healthcheck strategy in Kamal
585
+ # Add curl to work with the default health check strategy in Kamal
576
586
  packages = ["curl"]
577
587
 
578
588
  # ActiveRecord databases
@@ -606,6 +616,14 @@ module Rails
606
616
  packages.compact.sort
607
617
  end
608
618
 
619
+ def ci_packages
620
+ if depends_on_system_test?
621
+ dockerfile_build_packages << "google-chrome-stable"
622
+ else
623
+ dockerfile_build_packages
624
+ end
625
+ end
626
+
609
627
  def css_gemfile_entry
610
628
  return if options[:api]
611
629
  return unless options[:css]
@@ -620,35 +638,9 @@ module Rails
620
638
  end
621
639
 
622
640
  def cable_gemfile_entry
623
- return if options[:skip_action_cable]
624
-
625
- comment = "Use Redis adapter to run Action Cable in production"
626
- GemfileEntry.new("redis", ">= 4.0.1", comment, {}, true)
627
- end
628
-
629
- def bundle_command(command, env = {})
630
- say_status :run, "bundle #{command}"
631
-
632
- # We are going to shell out rather than invoking Bundler::CLI.new(command)
633
- # because `rails new` loads the Thor gem and on the other hand bundler uses
634
- # its own vendored Thor, which could be a different version. Running both
635
- # things in the same process is a recipe for a night with paracetamol.
636
- #
637
- # Thanks to James Tucker for the Gem tricks involved in this call.
638
- _bundle_command = Gem.bin_path("bundler", "bundle")
639
-
640
- require "bundler"
641
- Bundler.with_original_env do
642
- exec_bundle_command(_bundle_command, command, env)
643
- end
644
- end
645
-
646
- def exec_bundle_command(bundle_command, command, env)
647
- full_command = %Q["#{Gem.ruby}" "#{bundle_command}" #{command}]
648
- if options[:quiet]
649
- system(env, full_command, out: File::NULL)
650
- else
651
- system(env, full_command)
641
+ if !options[:skip_action_cable] && options[:skip_solid]
642
+ comment = "Use Redis adapter to run Action Cable in production"
643
+ GemfileEntry.new("redis", ">= 4.0.1", comment, {}, true)
652
644
  end
653
645
  end
654
646
 
@@ -656,10 +648,6 @@ module Rails
656
648
  !(options[:skip_bundle] || options[:pretend])
657
649
  end
658
650
 
659
- def bundler_windows_platforms
660
- Gem.rubygems_version >= Gem::Version.new("3.3.22") ? "windows" : "mswin mswin64 mingw x64_mingw"
661
- end
662
-
663
651
  def depends_on_system_test?
664
652
  !(options[:skip_system_test] || options[:skip_test] || options[:api])
665
653
  end
@@ -721,6 +709,25 @@ module Rails
721
709
  end
722
710
  end
723
711
 
712
+ def run_kamal
713
+ return if options[:skip_kamal] || !bundle_install?
714
+
715
+ bundle_command "binstubs kamal"
716
+ bundle_command "exec kamal init"
717
+
718
+ template "kamal-secrets.tt", ".kamal/secrets", force: true
719
+ template "config/deploy.yml", force: true
720
+ end
721
+
722
+ def run_solid
723
+ return if skip_solid? || !bundle_install?
724
+
725
+ commands = "solid_cache:install solid_queue:install"
726
+ commands += " solid_cable:install" unless skip_action_cable?
727
+
728
+ rails_command commands
729
+ end
730
+
724
731
  def add_bundler_platforms
725
732
  if bundle_install? && !jruby?
726
733
  # The vast majority of Rails apps will be deployed on `x86_64-linux`.
@@ -731,14 +738,27 @@ module Rails
731
738
  end
732
739
  end
733
740
 
741
+ def generate_bundler_binstub
742
+ if bundle_install?
743
+ bundle_command("binstubs bundler")
744
+ end
745
+ end
746
+
734
747
  def jruby?
735
748
  defined?(JRUBY_VERSION)
736
749
  end
737
750
 
738
- def generate_bundler_binstub
739
- if bundle_install?
740
- bundle_command("binstubs bundler")
751
+ def version_manager_ruby_version
752
+ return ENV["RBENV_VERSION"] if ENV["RBENV_VERSION"]
753
+ return ENV["rvm_ruby_string"] if ENV["rvm_ruby_string"]
754
+
755
+ version = if RUBY_ENGINE == "ruby"
756
+ Gem.ruby_version.to_s.sub(/\.([a-zA-Z])/, '-\1')
757
+ else
758
+ RUBY_ENGINE_VERSION
741
759
  end
760
+
761
+ "#{RUBY_ENGINE}-#{version}"
742
762
  end
743
763
 
744
764
  def empty_directory_with_keep_file(destination, config = {})