railties 7.1.3.4 → 8.0.1

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 (193) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +128 -775
  3. data/lib/minitest/rails_plugin.rb +6 -3
  4. data/lib/rails/all.rb +1 -3
  5. data/lib/rails/api/task.rb +6 -4
  6. data/lib/rails/application/bootstrap.rb +5 -7
  7. data/lib/rails/application/configuration.rb +81 -43
  8. data/lib/rails/application/default_middleware_stack.rb +4 -0
  9. data/lib/rails/application/dummy_config.rb +2 -2
  10. data/lib/rails/application/finisher.rb +9 -3
  11. data/lib/rails/application/routes_reloader.rb +16 -2
  12. data/lib/rails/application.rb +27 -86
  13. data/lib/rails/backtrace_cleaner.rb +19 -4
  14. data/lib/rails/cli.rb +0 -1
  15. data/lib/rails/code_statistics.rb +128 -86
  16. data/lib/rails/code_statistics_calculator.rb +78 -76
  17. data/lib/rails/command/helpers/editor.rb +1 -1
  18. data/lib/rails/command.rb +0 -6
  19. data/lib/rails/commands/app/update_command.rb +94 -0
  20. data/lib/rails/commands/boot/boot_command.rb +14 -0
  21. data/lib/rails/commands/console/console_command.rb +2 -21
  22. data/lib/rails/commands/console/irb_console.rb +128 -0
  23. data/lib/rails/commands/credentials/USAGE +4 -4
  24. data/lib/rails/commands/credentials/credentials_command.rb +7 -3
  25. data/lib/rails/commands/dbconsole/dbconsole_command.rb +21 -30
  26. data/lib/rails/commands/dev/dev_command.rb +1 -1
  27. data/lib/rails/commands/devcontainer/devcontainer_command.rb +40 -0
  28. data/lib/rails/commands/rake/rake_command.rb +1 -1
  29. data/lib/rails/commands/runner/runner_command.rb +14 -3
  30. data/lib/rails/commands/server/server_command.rb +5 -3
  31. data/lib/rails/commands/stats/stats_command.rb +19 -0
  32. data/lib/rails/commands/test/test_command.rb +2 -0
  33. data/lib/rails/configuration.rb +10 -1
  34. data/lib/rails/console/methods.rb +7 -0
  35. data/lib/rails/dev_caching.rb +2 -2
  36. data/lib/rails/engine/configuration.rb +3 -1
  37. data/lib/rails/engine/lazy_route_set.rb +114 -0
  38. data/lib/rails/engine.rb +16 -12
  39. data/lib/rails/gem_version.rb +4 -4
  40. data/lib/rails/generators/actions.rb +3 -3
  41. data/lib/rails/generators/app_base.rb +115 -68
  42. data/lib/rails/generators/base.rb +1 -1
  43. data/lib/rails/generators/database.rb +263 -71
  44. data/lib/rails/generators/erb/authentication/authentication_generator.rb +15 -0
  45. data/lib/rails/generators/erb/authentication/templates/app/views/passwords/edit.html.erb +9 -0
  46. data/lib/rails/generators/erb/authentication/templates/app/views/passwords/new.html.erb +8 -0
  47. data/lib/rails/generators/erb/authentication/templates/app/views/sessions/new.html.erb +11 -0
  48. data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +2 -0
  49. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +2 -0
  50. data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +2 -0
  51. data/lib/rails/generators/generated_attribute.rb +42 -12
  52. data/lib/rails/generators/migration.rb +3 -3
  53. data/lib/rails/generators/rails/app/app_generator.rb +75 -54
  54. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +33 -17
  55. data/lib/rails/generators/rails/app/templates/Gemfile.tt +38 -23
  56. data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css.tt +6 -11
  57. data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +4 -0
  58. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +17 -3
  59. data/lib/rails/generators/rails/app/templates/app/views/pwa/manifest.json.erb.tt +22 -0
  60. data/lib/rails/generators/rails/app/templates/app/views/pwa/service-worker.js +26 -0
  61. data/lib/rails/generators/rails/app/templates/bin/brakeman.tt +6 -0
  62. data/lib/rails/generators/rails/app/templates/bin/dev.tt +1 -0
  63. data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +7 -0
  64. data/lib/rails/generators/rails/app/templates/bin/setup.tt +6 -5
  65. data/lib/rails/generators/rails/app/templates/bin/thrust.tt +4 -0
  66. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +1 -1
  67. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +26 -3
  68. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +30 -0
  69. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +47 -0
  70. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +26 -3
  71. data/lib/rails/generators/rails/app/templates/config/deploy.yml.tt +128 -0
  72. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +22 -26
  73. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +36 -48
  74. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +7 -18
  75. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +0 -7
  76. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +1 -1
  77. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_0.rb.tt +30 -0
  78. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +35 -27
  79. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +6 -0
  80. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +7 -1
  81. data/lib/rails/generators/rails/app/templates/dockerignore.tt +20 -2
  82. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +144 -0
  83. data/lib/rails/generators/rails/app/templates/github/dependabot.yml +12 -0
  84. data/lib/rails/generators/rails/app/templates/gitignore.tt +4 -5
  85. data/lib/rails/generators/rails/app/templates/kamal-secrets.tt +17 -0
  86. data/lib/rails/generators/rails/app/templates/public/400.html +114 -0
  87. data/lib/rails/generators/rails/app/templates/public/404.html +113 -66
  88. data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +114 -0
  89. data/lib/rails/generators/rails/app/templates/public/422.html +113 -66
  90. data/lib/rails/generators/rails/app/templates/public/500.html +113 -65
  91. data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
  92. data/lib/rails/generators/rails/app/templates/public/icon.svg +3 -0
  93. data/lib/rails/generators/rails/app/templates/rubocop.yml.tt +8 -0
  94. data/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt +1 -1
  95. data/lib/rails/generators/rails/authentication/USAGE +6 -0
  96. data/lib/rails/generators/rails/authentication/authentication_generator.rb +58 -0
  97. data/lib/rails/generators/rails/authentication/templates/app/channels/application_cable/connection.rb.tt +16 -0
  98. data/lib/rails/generators/rails/authentication/templates/app/controllers/concerns/authentication.rb.tt +52 -0
  99. data/lib/rails/generators/rails/authentication/templates/app/controllers/passwords_controller.rb.tt +33 -0
  100. data/lib/rails/generators/rails/authentication/templates/app/controllers/sessions_controller.rb.tt +21 -0
  101. data/lib/rails/generators/rails/authentication/templates/app/mailers/passwords_mailer.rb.tt +6 -0
  102. data/lib/rails/generators/rails/authentication/templates/app/models/current.rb.tt +4 -0
  103. data/lib/rails/generators/rails/authentication/templates/app/models/session.rb.tt +3 -0
  104. data/lib/rails/generators/rails/authentication/templates/app/models/user.rb.tt +6 -0
  105. data/lib/rails/generators/rails/authentication/templates/app/views/passwords_mailer/reset.html.erb.tt +4 -0
  106. data/lib/rails/generators/rails/authentication/templates/app/views/passwords_mailer/reset.text.erb.tt +2 -0
  107. data/lib/rails/generators/rails/authentication/templates/test/mailers/previews/passwords_mailer_preview.rb.tt +7 -0
  108. data/lib/rails/generators/rails/controller/controller_generator.rb +1 -1
  109. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +4 -0
  110. data/lib/rails/generators/rails/db/system/change/change_generator.rb +132 -21
  111. data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +176 -0
  112. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +3 -0
  113. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/compose.yaml.tt +47 -0
  114. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +37 -0
  115. data/lib/rails/generators/rails/migration/migration_generator.rb +4 -0
  116. data/lib/rails/generators/rails/plugin/plugin_generator.rb +47 -16
  117. data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +2 -2
  118. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +6 -2
  119. data/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +2 -0
  120. data/lib/rails/generators/rails/plugin/templates/bin/rubocop.tt +7 -0
  121. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +103 -0
  122. data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +12 -0
  123. data/lib/rails/generators/rails/plugin/templates/rubocop.yml.tt +8 -0
  124. data/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt +1 -1
  125. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +2 -2
  126. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +2 -2
  127. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +3 -3
  128. data/lib/rails/generators/rails/script/USAGE +18 -0
  129. data/lib/rails/generators/rails/script/script_generator.rb +18 -0
  130. data/lib/rails/generators/rails/script/templates/script.rb.tt +3 -0
  131. data/lib/rails/generators/test_unit/authentication/authentication_generator.rb +14 -0
  132. data/lib/rails/generators/test_unit/authentication/templates/test/fixtures/users.yml.tt +9 -0
  133. data/lib/rails/generators/test_unit/authentication/templates/test/models/user_test.rb.tt +7 -0
  134. data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb.tt +6 -4
  135. data/lib/rails/generators/test_unit/mailer/templates/preview.rb.tt +3 -2
  136. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +15 -1
  137. data/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt +2 -2
  138. data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +2 -2
  139. data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +2 -0
  140. data/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt +1 -1
  141. data/lib/rails/generators/testing/assertions.rb +20 -0
  142. data/lib/rails/generators/testing/behavior.rb +7 -6
  143. data/lib/rails/generators.rb +7 -2
  144. data/lib/rails/health_controller.rb +1 -1
  145. data/lib/rails/info.rb +2 -2
  146. data/lib/rails/info_controller.rb +10 -2
  147. data/lib/rails/mailers_controller.rb +14 -1
  148. data/lib/rails/paths.rb +2 -2
  149. data/lib/rails/pwa_controller.rb +15 -0
  150. data/lib/rails/rack/logger.rb +15 -7
  151. data/lib/rails/rack/silence_request.rb +33 -0
  152. data/lib/rails/rack.rb +1 -0
  153. data/lib/rails/railtie/configurable.rb +2 -2
  154. data/lib/rails/railtie.rb +15 -16
  155. data/lib/rails/source_annotation_extractor.rb +31 -14
  156. data/lib/rails/tasks/framework.rake +0 -26
  157. data/lib/rails/tasks/statistics.rake +13 -28
  158. data/lib/rails/tasks/tmp.rake +1 -1
  159. data/lib/rails/templates/layouts/application.html.erb +1 -1
  160. data/lib/rails/templates/rails/info/notes.html.erb +65 -0
  161. data/lib/rails/templates/rails/mailers/email.html.erb +12 -8
  162. data/lib/rails/templates/rails/welcome/index.html.erb +4 -2
  163. data/lib/rails/test_help.rb +2 -4
  164. data/lib/rails/test_unit/reporter.rb +8 -2
  165. data/lib/rails/test_unit/runner.rb +27 -2
  166. data/lib/rails/test_unit/test_parser.rb +48 -0
  167. data/lib/rails.rb +7 -4
  168. metadata +77 -45
  169. data/lib/rails/app_updater.rb +0 -40
  170. data/lib/rails/commands/secrets/USAGE +0 -61
  171. data/lib/rails/commands/secrets/secrets_command.rb +0 -47
  172. data/lib/rails/console/app.rb +0 -35
  173. data/lib/rails/console/helpers.rb +0 -19
  174. data/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt +0 -2
  175. data/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb.tt +0 -4
  176. data/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb.tt +0 -4
  177. data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +0 -68
  178. data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt +0 -54
  179. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +0 -70
  180. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +0 -24
  181. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +0 -62
  182. data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +0 -53
  183. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_1.rb.tt +0 -284
  184. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +0 -13
  185. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon-precomposed.png +0 -0
  186. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon.png +0 -0
  187. data/lib/rails/generators/rails/app/templates/public/favicon.ico +0 -0
  188. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +0 -13
  189. data/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js.tt +0 -10
  190. data/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js.tt +0 -6
  191. data/lib/rails/generators/rails/plugin/templates/rails/javascripts.js.tt +0 -17
  192. data/lib/rails/ruby_version_check.rb +0 -17
  193. data/lib/rails/secrets.rb +0 -110
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "irb/helper_method"
4
+ require "irb/command"
5
+
6
+ module Rails
7
+ class Console
8
+ class RailsHelperBase < IRB::HelperMethod::Base
9
+ end
10
+
11
+ class ControllerHelper < RailsHelperBase
12
+ description "Gets helper methods available to ApplicationController."
13
+
14
+ # This method assumes an +ApplicationController+ exists, and that it extends ActionController::Base.
15
+ def execute
16
+ ApplicationController.helpers
17
+ end
18
+ end
19
+
20
+ class ControllerInstance < RailsHelperBase
21
+ description "Gets a new instance of ApplicationController."
22
+
23
+ # This method assumes an +ApplicationController+ exists, and that it extends ActionController::Base.
24
+ def execute
25
+ @controller ||= ApplicationController.new
26
+ end
27
+ end
28
+
29
+ class NewSession < RailsHelperBase
30
+ description "[Deprecated] Please use `app(true)` instead."
31
+
32
+ def execute(*)
33
+ app = Rails.application
34
+ session = ActionDispatch::Integration::Session.new(app)
35
+
36
+ # This makes app.url_for and app.foo_path available in the console
37
+ session.extend(app.routes.url_helpers)
38
+ session.extend(app.routes.mounted_helpers)
39
+
40
+ session
41
+ end
42
+ end
43
+
44
+ class AppInstance < NewSession
45
+ description "Creates a new ActionDispatch::Integration::Session and memoizes it. Use `app(true)` to create a new instance."
46
+
47
+ def execute(create = false)
48
+ @app_integration_instance = nil if create
49
+ @app_integration_instance ||= super
50
+ end
51
+ end
52
+
53
+ class ReloadHelper < RailsHelperBase
54
+ description "Reloads the Rails application."
55
+
56
+ def execute
57
+ puts "Reloading..."
58
+ Rails.application.reloader.reload!
59
+ end
60
+ end
61
+
62
+ IRB::HelperMethod.register(:helper, ControllerHelper)
63
+ IRB::HelperMethod.register(:controller, ControllerInstance)
64
+ IRB::HelperMethod.register(:new_session, NewSession)
65
+ IRB::HelperMethod.register(:app, AppInstance)
66
+ IRB::HelperMethod.register(:reload!, ReloadHelper)
67
+
68
+ class IRBConsole
69
+ def initialize(app)
70
+ @app = app
71
+
72
+ require "irb"
73
+ require "irb/completion"
74
+ end
75
+
76
+ def name
77
+ "IRB"
78
+ end
79
+
80
+ def start
81
+ IRB.setup(nil)
82
+
83
+ if !Rails.env.local? && !ENV.key?("IRB_USE_AUTOCOMPLETE")
84
+ IRB.conf[:USE_AUTOCOMPLETE] = false
85
+ end
86
+
87
+ env = colorized_env
88
+ prompt_prefix = "%N(#{env})"
89
+ IRB.conf[:IRB_NAME] = @app.name
90
+
91
+ IRB.conf[:PROMPT][:RAILS_PROMPT] = {
92
+ PROMPT_I: "#{prompt_prefix}> ",
93
+ PROMPT_S: "#{prompt_prefix}%l ",
94
+ PROMPT_C: "#{prompt_prefix}* ",
95
+ RETURN: "=> %s\n"
96
+ }
97
+
98
+ if current_filter = IRB.conf[:BACKTRACE_FILTER]
99
+ IRB.conf[:BACKTRACE_FILTER] = -> (backtrace) do
100
+ backtrace = current_filter.call(backtrace)
101
+ Rails.backtrace_cleaner.filter(backtrace)
102
+ end
103
+ else
104
+ IRB.conf[:BACKTRACE_FILTER] = -> (backtrace) do
105
+ Rails.backtrace_cleaner.filter(backtrace)
106
+ end
107
+ end
108
+
109
+ # Respect user's choice of prompt mode.
110
+ IRB.conf[:PROMPT_MODE] = :RAILS_PROMPT if IRB.conf[:PROMPT_MODE] == :DEFAULT
111
+ IRB::Irb.new.run(IRB.conf)
112
+ end
113
+
114
+ def colorized_env
115
+ case Rails.env
116
+ when "development"
117
+ IRB::Color.colorize("dev", [:BLUE])
118
+ when "test"
119
+ IRB::Color.colorize("test", [:BLUE])
120
+ when "production"
121
+ IRB::Color.colorize("prod", [:RED])
122
+ else
123
+ Rails.env
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -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
@@ -20,8 +20,8 @@ module Rails
20
20
  load_generators
21
21
 
22
22
  if environment_specified?
23
- @content_path = "config/credentials/#{environment}.yml.enc" unless config.key?(:content_path)
24
- @key_path = "config/credentials/#{environment}.key" unless config.key?(:key_path)
23
+ @content_path = "config/credentials/#{environment}.yml.enc" unless config.overridden?(:content_path)
24
+ @key_path = "config/credentials/#{environment}.key" unless config.overridden?(:key_path)
25
25
  end
26
26
 
27
27
  ensure_encryption_key_has_been_added
@@ -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
@@ -16,28 +16,29 @@ module Rails
16
16
 
17
17
  def start
18
18
  adapter_class.dbconsole(db_config, @options)
19
- rescue NotImplementedError
20
- abort "Unknown command-line client for #{db_config.database}."
19
+ rescue NotImplementedError, ActiveRecord::AdapterNotFound, LoadError => error
20
+ abort error.message
21
21
  end
22
22
 
23
23
  def db_config
24
- return @db_config if defined?(@db_config)
25
-
26
- # If the user provided a database, use that. Otherwise find
27
- # the first config in the database.yml
28
- if database
29
- @db_config = configurations.configs_for(env_name: environment, name: database, include_hidden: true)
30
- else
31
- @db_config = configurations.find_db_config(environment)
32
- end
24
+ @db_config ||= begin
25
+ # If the user provided a database, use that. Otherwise find
26
+ # the first config in the database.yml
27
+ config = if database
28
+ @db_config = configurations.configs_for(env_name: environment, name: database, include_hidden: true)
29
+ else
30
+ @db_config = configurations.find_db_config(environment)
31
+ end
33
32
 
34
- unless @db_config
35
- missing_db = database ? "'#{database}' database is not" : "No databases are"
36
- raise ActiveRecord::AdapterNotSpecified,
37
- "#{missing_db} configured for '#{environment}'. Available configuration: #{configurations.inspect}"
38
- end
33
+ unless config
34
+ missing_db = database ? "'#{database}' database is not" : "No databases are"
35
+ raise ActiveRecord::AdapterNotSpecified,
36
+ "#{missing_db} configured for '#{environment}'. Available configuration: #{configurations.inspect}"
37
+ end
39
38
 
40
- @db_config
39
+ config.validate!
40
+ config
41
+ end
41
42
  end
42
43
 
43
44
  def database
@@ -50,11 +51,9 @@ module Rails
50
51
 
51
52
  private
52
53
  def adapter_class
53
- if ActiveRecord::Base.respond_to?(db_config.adapter_class_method)
54
- ActiveRecord::Base.public_send(db_config.adapter_class_method)
55
- else
56
- ActiveRecord::ConnectionAdapters::AbstractAdapter
57
- end
54
+ ActiveRecord::ConnectionAdapters.resolve(db_config.adapter)
55
+ rescue LoadError
56
+ ActiveRecord::ConnectionAdapters::AbstractAdapter
58
57
  end
59
58
 
60
59
  def configurations # :doc:
@@ -62,14 +61,6 @@ module Rails
62
61
  ActiveRecord::Base.configurations = Rails.application.config.database_configuration
63
62
  ActiveRecord::Base.configurations
64
63
  end
65
-
66
- def find_cmd_and_exec(commands, *args) # :doc:
67
- Rails.deprecator.warn(<<~MSG.squish)
68
- Rails::DBConsole#find_cmd_and_exec is deprecated and will be removed in Rails 7.2.
69
- Please use find_cmd_and_exec on the connection adapter class instead.
70
- MSG
71
- ActiveRecord::Base.connection.find_cmd_and_exec(commands, *args)
72
- end
73
64
  end
74
65
 
75
66
  module Command
@@ -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
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/rails/devcontainer/devcontainer_generator"
5
+
6
+ module Rails
7
+ module Command
8
+ class DevcontainerCommand < Base # :nodoc:
9
+ desc "devcontainer", "Generate a Dev Container setup based on current application configuration"
10
+ def perform(*)
11
+ boot_application!
12
+
13
+ say "Generating Dev Container with the following options:"
14
+ devcontainer_options.each do |option, value|
15
+ say "#{option}: #{value}"
16
+ end
17
+
18
+ Rails::Generators::DevcontainerGenerator.new([], devcontainer_options).invoke_all
19
+ end
20
+
21
+ private
22
+ def devcontainer_options
23
+ @devcontainer_options ||= {
24
+ app_name: Rails.application.railtie_name.chomp("_application"),
25
+ database: !!defined?(ActiveRecord) && database,
26
+ active_storage: !!defined?(ActiveStorage),
27
+ redis: !!((defined?(ActionCable) && !defined?(SolidCable)) || (defined?(ActiveJob) && !defined?(SolidQueue))),
28
+ system_test: File.exist?("test/application_system_test_case.rb"),
29
+ node: File.exist?(".node-version"),
30
+ kamal: File.exist?("config/deploy.yml"),
31
+ }
32
+ end
33
+
34
+ def database
35
+ adapter = ActiveRecord::Base.connection_db_config.adapter
36
+ adapter == "mysql2" ? "mysql" : adapter
37
+ end
38
+ end
39
+ end
40
+ end
@@ -18,7 +18,7 @@ module Rails
18
18
 
19
19
  def perform(task, args, config)
20
20
  with_rake(task, *args) do |rake|
21
- if unrecognized_task = rake.top_level_tasks.find { |task| !rake.lookup(task[/[^\[]+/]) }
21
+ if unrecognized_task = (rake.top_level_tasks - ["default"]).find { |task| !rake.lookup(task[/[^\[]+/]) }
22
22
  @rake_tasks = rake.tasks
23
23
  raise UnrecognizedCommandError.new(unrecognized_task)
24
24
  end
@@ -7,6 +7,8 @@ module Rails
7
7
  class RunnerCommand < Base # :nodoc:
8
8
  include EnvironmentArgument
9
9
 
10
+ class_option :skip_executor, type: :boolean, aliases: "-w", desc: "Don't wrap with Rails Executor", default: false
11
+
10
12
  no_commands do
11
13
  def help(command_name = nil, *)
12
14
  super
@@ -30,19 +32,20 @@ module Rails
30
32
 
31
33
  ARGV.replace(command_argv)
32
34
 
35
+ wrap_with_executor = !options[:skip_executor]
33
36
  if code_or_file == "-"
34
- Rails.application.executor.wrap(source: "application.runner.railties") do
37
+ conditional_executor(wrap_with_executor, source: "application.runner.railties") do
35
38
  eval($stdin.read, TOPLEVEL_BINDING, "stdin")
36
39
  end
37
40
  elsif File.exist?(code_or_file)
38
41
  expanded_file_path = File.expand_path code_or_file
39
42
  $0 = expanded_file_path
40
- Rails.application.executor.wrap(source: "application.runner.railties") do
43
+ conditional_executor(wrap_with_executor, source: "application.runner.railties") do
41
44
  Kernel.load expanded_file_path
42
45
  end
43
46
  else
44
47
  begin
45
- Rails.application.executor.wrap(source: "application.runner.railties") do
48
+ conditional_executor(wrap_with_executor, source: "application.runner.railties") do
46
49
  eval(code_or_file, TOPLEVEL_BINDING, __FILE__, __LINE__)
47
50
  end
48
51
  rescue SyntaxError, NameError => e
@@ -62,6 +65,14 @@ module Rails
62
65
  end
63
66
 
64
67
  private
68
+ def conditional_executor(enabled, **args, &block)
69
+ if enabled
70
+ Rails.application.executor.wrap(**args, &block)
71
+ else
72
+ yield
73
+ end
74
+ end
75
+
65
76
  def looks_like_a_file_path?(code_or_file)
66
77
  code_or_file.ends_with?(".rb")
67
78
  end
@@ -114,7 +114,7 @@ module Rails
114
114
  class_option :using, aliases: "-u", type: :string,
115
115
  desc: "Specify the Rack server used to run the application (thin/puma/webrick).", banner: :name
116
116
  class_option :pid, aliases: "-P", type: :string,
117
- desc: "Specify the PID file - defaults to #{DEFAULT_PIDFILE}."
117
+ desc: "Specify the PID file. Defaults to #{DEFAULT_PIDFILE} in development."
118
118
  class_option :dev_caching, aliases: "-C", type: :boolean, default: nil,
119
119
  desc: "Specify whether to perform caching in development."
120
120
  class_option :restart, type: :boolean, default: nil, hide: true
@@ -243,11 +243,13 @@ module Rails
243
243
  end
244
244
 
245
245
  def pid
246
- File.expand_path(options[:pid] || ENV.fetch("PIDFILE", DEFAULT_PIDFILE))
246
+ default_pidfile = environment == "development" ? DEFAULT_PIDFILE : nil
247
+ pid = options[:pid] || ENV["PIDFILE"] || default_pidfile
248
+ File.expand_path(pid) if pid
247
249
  end
248
250
 
249
251
  def prepare_restart
250
- FileUtils.rm_f(pid) if options[:restart]
252
+ FileUtils.rm_f(pid) if pid && options[:restart]
251
253
  end
252
254
 
253
255
  def rack_server_suggestion(server)
@@ -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
@@ -31,6 +31,8 @@ module Rails
31
31
  Rails::TestUnit::Runner.parse_options(args)
32
32
  run_prepare_task if self.args.none?(EXACT_TEST_ARGUMENT_PATTERN)
33
33
  Rails::TestUnit::Runner.run(args)
34
+ rescue Rails::TestUnit::InvalidTestError => error
35
+ raise ArgumentError, error.message
34
36
  end
35
37
 
36
38
  # Define Thor tasks to avoid going through Rake and booting twice when using bin/rails test:*
@@ -131,8 +131,17 @@ module Rails
131
131
  @after_generate_callbacks << block
132
132
  end
133
133
 
134
+ def apply_rubocop_autocorrect_after_generate!
135
+ after_generate do |files|
136
+ parsable_files = files.filter { |file| File.exist?(file) && file.end_with?(".rb") }
137
+ unless parsable_files.empty?
138
+ system(RbConfig.ruby, "bin/rubocop", "-A", "--fail-level=E", "--format=quiet", *parsable_files, exception: true)
139
+ end
140
+ end
141
+ end
142
+
134
143
  def method_missing(method, *args)
135
- method = method.to_s.delete_suffix("=").to_sym
144
+ method = method.name.delete_suffix("=").to_sym
136
145
 
137
146
  if args.empty?
138
147
  if method == :rails
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
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,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "action_dispatch/routing/route_set"
6
+
7
+ module Rails
8
+ class Engine
9
+ class LazyRouteSet < ActionDispatch::Routing::RouteSet # :nodoc:
10
+ class NamedRouteCollection < ActionDispatch::Routing::RouteSet::NamedRouteCollection
11
+ def route_defined?(name)
12
+ Rails.application&.reload_routes_unless_loaded
13
+ super
14
+ end
15
+ end
16
+
17
+ module ProxyUrlHelpers
18
+ def url_for(options)
19
+ Rails.application&.reload_routes_unless_loaded
20
+ super
21
+ end
22
+
23
+ def full_url_for(options)
24
+ Rails.application&.reload_routes_unless_loaded
25
+ super
26
+ end
27
+
28
+ def route_for(name, *args)
29
+ Rails.application&.reload_routes_unless_loaded
30
+ super
31
+ end
32
+
33
+ def optimize_routes_generation?
34
+ Rails.application&.reload_routes_unless_loaded
35
+ super
36
+ end
37
+
38
+ def polymorphic_url(record_or_hash_or_array, options = {})
39
+ Rails.application&.reload_routes_unless_loaded
40
+ super
41
+ end
42
+
43
+ def polymorphic_path(record_or_hash_or_array, options = {})
44
+ Rails.application&.reload_routes_unless_loaded
45
+ super
46
+ end
47
+ end
48
+
49
+ def initialize(config = DEFAULT_CONFIG)
50
+ super
51
+ self.named_routes = NamedRouteCollection.new
52
+ named_routes.url_helpers_module.prepend(method_missing_module)
53
+ named_routes.path_helpers_module.prepend(method_missing_module)
54
+ end
55
+
56
+ def generate_extras(options, recall = {})
57
+ Rails.application&.reload_routes_unless_loaded
58
+
59
+ super(options, recall)
60
+ end
61
+
62
+ def generate_url_helpers(supports_path)
63
+ super.tap { |mod| mod.singleton_class.prepend(ProxyUrlHelpers) }
64
+ end
65
+
66
+ def call(req)
67
+ Rails.application&.reload_routes_unless_loaded
68
+ super
69
+ end
70
+
71
+ def draw(&block)
72
+ Rails.application&.reload_routes_unless_loaded
73
+ super
74
+ end
75
+
76
+ def recognize_path(path, environment = {})
77
+ Rails.application&.reload_routes_unless_loaded
78
+ super
79
+ end
80
+
81
+ def recognize_path_with_request(...)
82
+ Rails.application&.reload_routes_unless_loaded
83
+ super
84
+ end
85
+
86
+ def routes
87
+ Rails.application&.reload_routes_unless_loaded
88
+ super
89
+ end
90
+
91
+ private
92
+ def method_missing_module
93
+ @method_missing_module ||= Module.new do
94
+ private
95
+ def method_missing(...)
96
+ if Rails.application&.reload_routes_unless_loaded
97
+ public_send(...)
98
+ else
99
+ super
100
+ end
101
+ end
102
+
103
+ def respond_to_missing?(...)
104
+ if Rails.application&.reload_routes_unless_loaded
105
+ respond_to?(...)
106
+ else
107
+ super
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end