railties 5.2.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (234) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +293 -89
  3. data/MIT-LICENSE +1 -1
  4. data/RDOC_MAIN.rdoc +39 -33
  5. data/README.rdoc +3 -3
  6. data/lib/minitest/rails_plugin.rb +24 -13
  7. data/lib/rails/all.rb +4 -0
  8. data/lib/rails/api/generator.rb +2 -1
  9. data/lib/rails/api/task.rb +17 -0
  10. data/lib/rails/app_loader.rb +2 -2
  11. data/lib/rails/app_updater.rb +4 -1
  12. data/lib/rails/application/bootstrap.rb +9 -17
  13. data/lib/rails/application/configuration.rb +177 -27
  14. data/lib/rails/application/default_middleware_stack.rb +7 -3
  15. data/lib/rails/application/dummy_erb_compiler.rb +18 -0
  16. data/lib/rails/application/finisher.rb +69 -2
  17. data/lib/rails/application/routes_reloader.rb +9 -19
  18. data/lib/rails/application.rb +96 -66
  19. data/lib/rails/application_controller.rb +0 -1
  20. data/lib/rails/autoloaders.rb +48 -0
  21. data/lib/rails/backtrace_cleaner.rb +14 -21
  22. data/lib/rails/code_statistics.rb +8 -6
  23. data/lib/rails/code_statistics_calculator.rb +6 -6
  24. data/lib/rails/command/actions.rb +10 -0
  25. data/lib/rails/command/base.rb +17 -5
  26. data/lib/rails/command/behavior.rb +8 -49
  27. data/lib/rails/command/environment_argument.rb +9 -16
  28. data/lib/rails/command/spellchecker.rb +57 -0
  29. data/lib/rails/command.rb +18 -11
  30. data/lib/rails/commands/console/console_command.rb +6 -0
  31. data/lib/rails/commands/credentials/USAGE +33 -0
  32. data/lib/rails/commands/credentials/credentials_command/diffing.rb +41 -0
  33. data/lib/rails/commands/credentials/credentials_command.rb +78 -21
  34. data/lib/rails/commands/db/system/change/change_command.rb +25 -0
  35. data/lib/rails/commands/dbconsole/dbconsole_command.rb +66 -51
  36. data/lib/rails/commands/dev/dev_command.rb +19 -0
  37. data/lib/rails/commands/encrypted/USAGE +28 -0
  38. data/lib/rails/commands/encrypted/encrypted_command.rb +5 -4
  39. data/lib/rails/commands/generate/generate_command.rb +1 -1
  40. data/lib/rails/commands/help/help_command.rb +1 -1
  41. data/lib/rails/commands/initializers/initializers_command.rb +23 -0
  42. data/lib/rails/commands/new/new_command.rb +2 -2
  43. data/lib/rails/commands/notes/notes_command.rb +29 -0
  44. data/lib/rails/commands/plugin/plugin_command.rb +1 -1
  45. data/lib/rails/commands/rake/rake_command.rb +9 -8
  46. data/lib/rails/commands/routes/routes_command.rb +37 -0
  47. data/lib/rails/commands/runner/runner_command.rb +13 -9
  48. data/lib/rails/commands/secrets/USAGE +6 -0
  49. data/lib/rails/commands/secrets/secrets_command.rb +3 -3
  50. data/lib/rails/commands/server/server_command.rb +92 -56
  51. data/lib/rails/commands/test/test_command.rb +2 -2
  52. data/lib/rails/configuration.rb +48 -19
  53. data/lib/rails/engine/configuration.rb +6 -2
  54. data/lib/rails/engine/updater.rb +1 -1
  55. data/lib/rails/engine.rb +63 -35
  56. data/lib/rails/gem_version.rb +2 -2
  57. data/lib/rails/generators/actions/create_migration.rb +5 -1
  58. data/lib/rails/generators/actions.rb +89 -56
  59. data/lib/rails/generators/app_base.rb +80 -108
  60. data/lib/rails/generators/app_name.rb +50 -0
  61. data/lib/rails/generators/base.rb +19 -12
  62. data/lib/rails/generators/database.rb +57 -0
  63. data/lib/rails/generators/erb/mailer/mailer_generator.rb +1 -2
  64. data/lib/rails/generators/erb/scaffold/scaffold_generator.rb +0 -1
  65. data/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt +7 -4
  66. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +1 -1
  67. data/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt +9 -1
  68. data/lib/rails/generators/erb.rb +0 -1
  69. data/lib/rails/generators/generated_attribute.rb +50 -31
  70. data/lib/rails/generators/migration.rb +3 -3
  71. data/lib/rails/generators/model_helpers.rb +33 -2
  72. data/lib/rails/generators/named_base.rb +3 -7
  73. data/lib/rails/generators/rails/app/USAGE +2 -1
  74. data/lib/rails/generators/rails/app/app_generator.rb +127 -84
  75. data/lib/rails/generators/rails/app/templates/Gemfile.tt +18 -21
  76. data/lib/rails/generators/rails/app/templates/Rakefile.tt +1 -1
  77. data/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt +0 -3
  78. data/lib/rails/generators/rails/app/templates/app/javascript/channels/consumer.js +6 -0
  79. data/lib/rails/generators/rails/app/templates/app/javascript/channels/index.js +5 -0
  80. data/lib/rails/generators/rails/app/templates/app/javascript/packs/application.js.tt +23 -0
  81. data/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb.tt +5 -0
  82. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +6 -5
  83. data/lib/rails/generators/rails/app/templates/bin/rails.tt +5 -2
  84. data/lib/rails/generators/rails/app/templates/bin/rake.tt +5 -2
  85. data/lib/rails/generators/rails/app/templates/bin/setup.tt +9 -9
  86. data/lib/rails/generators/rails/app/templates/bin/spring.tt +9 -0
  87. data/lib/rails/generators/rails/app/templates/bin/yarn.tt +11 -3
  88. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +16 -7
  89. data/lib/rails/generators/rails/app/templates/config/boot.rb.tt +2 -2
  90. data/lib/rails/generators/rails/app/templates/config/cable.yml.tt +1 -1
  91. data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +4 -5
  92. data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt +12 -11
  93. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +13 -12
  94. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +1 -1
  95. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +13 -12
  96. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +12 -11
  97. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +16 -15
  98. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +1 -1
  99. data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +11 -10
  100. data/lib/rails/generators/rails/app/templates/config/environment.rb.tt +1 -1
  101. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +22 -5
  102. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +43 -17
  103. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +26 -7
  104. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +1 -1
  105. data/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt +4 -3
  106. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +7 -0
  107. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +3 -1
  108. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_1.rb.tt +63 -0
  109. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +11 -0
  110. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +1 -1
  111. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +13 -4
  112. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +1 -1
  113. data/lib/rails/generators/rails/app/templates/config/spring.rb.tt +6 -6
  114. data/lib/rails/generators/rails/app/templates/config.ru.tt +2 -1
  115. data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +1 -1
  116. data/lib/rails/generators/rails/app/templates/gitattributes.tt +14 -0
  117. data/lib/rails/generators/rails/app/templates/gitignore.tt +10 -7
  118. data/lib/rails/generators/rails/app/templates/package.json.tt +8 -2
  119. data/lib/rails/generators/rails/app/templates/public/robots.txt +1 -1
  120. data/lib/rails/generators/rails/app/templates/ruby-version.tt +1 -1
  121. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +11 -0
  122. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +9 -2
  123. data/lib/rails/generators/rails/assets/USAGE +3 -7
  124. data/lib/rails/generators/rails/assets/assets_generator.rb +0 -1
  125. data/lib/rails/generators/rails/benchmark/USAGE +19 -0
  126. data/lib/rails/generators/rails/benchmark/benchmark_generator.rb +29 -0
  127. data/lib/rails/generators/rails/benchmark/templates/benchmark.rb.tt +15 -0
  128. data/lib/rails/generators/rails/controller/USAGE +2 -2
  129. data/lib/rails/generators/rails/controller/controller_generator.rb +10 -39
  130. data/lib/rails/generators/rails/credentials/credentials_generator.rb +6 -7
  131. data/lib/rails/generators/rails/db/system/change/change_generator.rb +65 -0
  132. data/lib/rails/generators/rails/encrypted_file/encrypted_file_generator.rb +10 -7
  133. data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +1 -0
  134. data/lib/rails/generators/rails/generator/USAGE +2 -2
  135. data/lib/rails/generators/rails/generator/generator_generator.rb +0 -1
  136. data/lib/rails/generators/rails/generator/templates/USAGE.tt +1 -1
  137. data/lib/rails/generators/rails/helper/USAGE +2 -3
  138. data/lib/rails/generators/rails/helper/helper_generator.rb +5 -0
  139. data/lib/rails/generators/rails/integration_test/USAGE +2 -2
  140. data/lib/rails/generators/rails/migration/USAGE +4 -4
  141. data/lib/rails/generators/rails/model/USAGE +15 -16
  142. data/lib/rails/generators/rails/plugin/plugin_generator.rb +32 -56
  143. data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +18 -18
  144. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +3 -10
  145. data/lib/rails/generators/rails/plugin/templates/Rakefile.tt +4 -18
  146. data/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt +1 -2
  147. data/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt +1 -1
  148. data/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt +1 -1
  149. data/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt +1 -1
  150. data/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt +1 -1
  151. data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +3 -3
  152. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +14 -11
  153. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt +1 -1
  154. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/railtie.rb.tt +1 -1
  155. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb.tt +1 -0
  156. data/lib/rails/generators/rails/plugin/templates/rails/boot.rb.tt +1 -1
  157. data/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb.tt +4 -4
  158. data/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb.tt +1 -1
  159. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +0 -4
  160. data/lib/rails/generators/rails/resource/USAGE +4 -4
  161. data/lib/rails/generators/rails/resource_route/resource_route_generator.rb +2 -27
  162. data/lib/rails/generators/rails/scaffold/USAGE +5 -5
  163. data/lib/rails/generators/rails/scaffold_controller/USAGE +2 -2
  164. data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +19 -0
  165. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +2 -2
  166. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +2 -2
  167. data/lib/rails/generators/rails/system_test/USAGE +2 -2
  168. data/lib/rails/generators/rails/task/USAGE +3 -3
  169. data/lib/rails/generators/resource_helpers.rb +1 -6
  170. data/lib/rails/generators/test_case.rb +1 -1
  171. data/lib/rails/generators/test_unit/controller/controller_generator.rb +2 -0
  172. data/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt +3 -3
  173. data/lib/rails/generators/test_unit/generator/generator_generator.rb +0 -1
  174. data/lib/rails/generators/test_unit/generator/templates/generator_test.rb.tt +2 -2
  175. data/lib/rails/generators/test_unit/integration/integration_generator.rb +5 -0
  176. data/lib/rails/generators/test_unit/integration/templates/integration_test.rb.tt +1 -1
  177. data/lib/rails/generators/test_unit/job/job_generator.rb +5 -0
  178. data/lib/rails/generators/test_unit/job/templates/unit_test.rb.tt +1 -1
  179. data/lib/rails/generators/test_unit/mailer/mailer_generator.rb +1 -1
  180. data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb.tt +1 -1
  181. data/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt +3 -3
  182. data/lib/rails/generators/test_unit/model/templates/unit_test.rb.tt +1 -1
  183. data/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt +1 -1
  184. data/lib/rails/generators/test_unit/plugin/templates/test_helper.rb +2 -2
  185. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +12 -3
  186. data/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt +1 -1
  187. data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +1 -1
  188. data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +10 -2
  189. data/lib/rails/generators/test_unit/system/system_generator.rb +5 -0
  190. data/lib/rails/generators/testing/assertions.rb +2 -2
  191. data/lib/rails/generators/testing/behaviour.rb +4 -2
  192. data/lib/rails/generators.rb +38 -24
  193. data/lib/rails/info.rb +4 -4
  194. data/lib/rails/info_controller.rb +2 -3
  195. data/lib/rails/mailers_controller.rb +10 -4
  196. data/lib/rails/paths.rb +26 -10
  197. data/lib/rails/rack/logger.rb +5 -6
  198. data/lib/rails/railtie/configurable.rb +0 -1
  199. data/lib/rails/railtie/configuration.rb +3 -3
  200. data/lib/rails/railtie.rb +33 -13
  201. data/lib/rails/ruby_version_check.rb +3 -3
  202. data/lib/rails/secrets.rb +0 -1
  203. data/lib/rails/source_annotation_extractor.rb +124 -117
  204. data/lib/rails/tasks/engine.rake +1 -4
  205. data/lib/rails/tasks/framework.rake +13 -3
  206. data/lib/rails/tasks/log.rake +0 -1
  207. data/lib/rails/tasks/misc.rake +1 -1
  208. data/lib/rails/tasks/statistics.rake +5 -1
  209. data/lib/rails/tasks/yarn.rake +14 -1
  210. data/lib/rails/tasks/zeitwerk.rake +69 -0
  211. data/lib/rails/tasks.rb +1 -4
  212. data/lib/rails/templates/rails/mailers/email.html.erb +11 -7
  213. data/lib/rails/templates/rails/welcome/index.html.erb +3 -3
  214. data/lib/rails/test_help.rb +11 -9
  215. data/lib/rails/test_unit/reporter.rb +3 -2
  216. data/lib/rails/test_unit/runner.rb +25 -8
  217. data/lib/rails/test_unit/testing.rake +7 -1
  218. data/lib/rails.rb +10 -8
  219. metadata +45 -39
  220. data/lib/rails/generators/js/assets/assets_generator.rb +0 -15
  221. data/lib/rails/generators/js/assets/templates/javascript.js +0 -2
  222. data/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +0 -22
  223. data/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js.tt +0 -13
  224. data/lib/rails/generators/rails/app/templates/bin/bundle.tt +0 -2
  225. data/lib/rails/generators/rails/app/templates/bin/update.tt +0 -34
  226. data/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml.tt +0 -50
  227. data/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml.tt +0 -86
  228. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt +0 -35
  229. data/lib/rails/generators/rails/assets/templates/javascript.js +0 -2
  230. data/lib/rails/generators/rails/plugin/templates/rails/application.rb.tt +0 -23
  231. data/lib/rails/tasks/annotations.rake +0 -22
  232. data/lib/rails/tasks/dev.rake +0 -10
  233. data/lib/rails/tasks/initializers.rake +0 -8
  234. data/lib/rails/tasks/routes.rake +0 -31
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/string/inflections"
4
+ require "active_support/core_ext/array/conversions"
5
+
3
6
  module Rails
4
7
  class Application
5
8
  module Finisher
@@ -21,6 +24,64 @@ module Rails
21
24
  end
22
25
  end
23
26
 
27
+ # This will become an error if/when we remove classic mode. The plan is
28
+ # autoloaders won't be configured up to this point in the finisher, so
29
+ # constants just won't be found, raising regular NameError exceptions.
30
+ initializer :warn_if_autoloaded, before: :let_zeitwerk_take_over do
31
+ next if config.cache_classes
32
+ next if ActiveSupport::Dependencies.autoloaded_constants.empty?
33
+
34
+ autoloaded = ActiveSupport::Dependencies.autoloaded_constants
35
+ constants = "constant".pluralize(autoloaded.size)
36
+ enum = autoloaded.to_sentence
37
+ have = autoloaded.size == 1 ? "has" : "have"
38
+ these = autoloaded.size == 1 ? "This" : "These"
39
+ example = autoloaded.first
40
+ example_klass = example.constantize.class
41
+
42
+ if config.autoloader == :zeitwerk
43
+ ActiveSupport::DescendantsTracker.clear
44
+ ActiveSupport::Dependencies.clear
45
+
46
+ unload_message = "#{these} autoloaded #{constants} #{have} been unloaded."
47
+ else
48
+ unload_message = "`config.autoloader` is set to `#{config.autoloader}`. #{these} autoloaded #{constants} would have been unloaded if `config.autoloader` had been set to `:zeitwerk`."
49
+ end
50
+
51
+ ActiveSupport::Deprecation.warn(<<~WARNING)
52
+ Initialization autoloaded the #{constants} #{enum}.
53
+
54
+ Being able to do this is deprecated. Autoloading during initialization is going
55
+ to be an error condition in future versions of Rails.
56
+
57
+ Reloading does not reboot the application, and therefore code executed during
58
+ initialization does not run again. So, if you reload #{example}, for example,
59
+ the expected changes won't be reflected in that stale #{example_klass} object.
60
+
61
+ #{unload_message}
62
+
63
+ In order to autoload safely at boot time, please wrap your code in a reloader
64
+ callback this way:
65
+
66
+ Rails.application.reloader.to_prepare do
67
+ # Autoload classes and modules needed at boot time here.
68
+ end
69
+
70
+ That block runs when the application boots, and every time there is a reload.
71
+ For historical reasons, it may run twice, so it has to be idempotent.
72
+
73
+ Check the "Autoloading and Reloading Constants" guide to learn more about how
74
+ Rails autoloads and reloads.
75
+ WARNING
76
+ end
77
+
78
+ initializer :let_zeitwerk_take_over do
79
+ if config.autoloader == :zeitwerk
80
+ require "active_support/dependencies/zeitwerk_integration"
81
+ ActiveSupport::Dependencies::ZeitwerkIntegration.take_over(enable_reloading: !config.cache_classes)
82
+ end
83
+ end
84
+
24
85
  initializer :add_builtin_route do |app|
25
86
  if Rails.env.development?
26
87
  app.routes.prepend do
@@ -66,6 +127,10 @@ module Rails
66
127
  initializer :eager_load! do
67
128
  if config.eager_load
68
129
  ActiveSupport.run_load_hooks(:before_eager_load, self)
130
+ # Checks defined?(Zeitwerk) instead of zeitwerk_enabled? because we
131
+ # want to eager load any dependency managed by Zeitwerk regardless of
132
+ # the autoloading mode of the application.
133
+ Zeitwerk::Loader.eager_load_all if defined?(Zeitwerk)
69
134
  config.eager_load_namespaces.each(&:eager_load!)
70
135
  end
71
136
  end
@@ -127,7 +192,7 @@ module Rails
127
192
  initializer :set_routes_reloader_hook do |app|
128
193
  reloader = routes_reloader
129
194
  reloader.eager_load = app.config.eager_load
130
- reloader.execute_if_updated
195
+ reloader.execute
131
196
  reloaders << reloader
132
197
  app.reloader.to_run do
133
198
  # We configure #execute rather than #execute_if_updated because if
@@ -162,7 +227,9 @@ module Rails
162
227
  app.reloader.check = lambda { true }
163
228
  end
164
229
 
165
- if config.reload_classes_only_on_change
230
+ if config.cache_classes
231
+ # No reloader
232
+ elsif config.reload_classes_only_on_change
166
233
  reloader = config.file_watcher.new(*watchable_args, &callback)
167
234
  reloaders << reloader
168
235
 
@@ -5,13 +5,14 @@ require "active_support/core_ext/module/delegation"
5
5
  module Rails
6
6
  class Application
7
7
  class RoutesReloader
8
- attr_reader :route_sets, :paths
8
+ attr_reader :route_sets, :paths, :external_routes
9
9
  attr_accessor :eager_load
10
- delegate :updated?, to: :updater
10
+ delegate :execute_if_updated, :execute, :updated?, to: :updater
11
11
 
12
12
  def initialize
13
13
  @paths = []
14
14
  @route_sets = []
15
+ @external_routes = []
15
16
  @eager_load = false
16
17
  end
17
18
 
@@ -19,30 +20,19 @@ module Rails
19
20
  clear!
20
21
  load_paths
21
22
  finalize!
23
+ route_sets.each(&:eager_load!) if eager_load
22
24
  ensure
23
25
  revert
24
26
  end
25
27
 
26
- def execute
27
- ret = updater.execute
28
- route_sets.each(&:eager_load!) if eager_load
29
- ret
30
- end
31
-
32
- def execute_if_updated
33
- if updated = updater.execute_if_updated
34
- route_sets.each(&:eager_load!) if eager_load
35
- end
36
- updated
37
- end
38
-
39
28
  private
40
-
41
29
  def updater
42
30
  @updater ||= begin
43
- updater = ActiveSupport::FileUpdateChecker.new(paths) { reload! }
44
- updater.execute
45
- updater
31
+ dirs = @external_routes.each_with_object({}) do |dir, hash|
32
+ hash[dir.to_s] = %w(rb)
33
+ end
34
+
35
+ ActiveSupport::FileUpdateChecker.new(paths, dirs) { reload! }
46
36
  end
47
37
  end
48
38
 
@@ -6,7 +6,8 @@ require "active_support/core_ext/object/blank"
6
6
  require "active_support/key_generator"
7
7
  require "active_support/message_verifier"
8
8
  require "active_support/encrypted_configuration"
9
- require "active_support/deprecation"
9
+ require "active_support/hash_with_indifferent_access"
10
+ require "active_support/configuration_file"
10
11
  require "rails/engine"
11
12
  require "rails/secrets"
12
13
 
@@ -44,7 +45,7 @@ module Rails
44
45
  # process. From the moment you require "config/application.rb" in your app,
45
46
  # the booting process goes like this:
46
47
  #
47
- # 1) require "config/boot.rb" to setup load paths
48
+ # 1) require "config/boot.rb" to set up load paths
48
49
  # 2) require railties and engines
49
50
  # 3) Define Rails.application as "class MyApp::Application < Rails::Application"
50
51
  # 4) Run config.before_configuration callbacks
@@ -172,14 +173,9 @@ module Rails
172
173
  def key_generator
173
174
  # number of iterations selected based on consultation with the google security
174
175
  # team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220
175
- @caching_key_generator ||=
176
- if secret_key_base
177
- ActiveSupport::CachingKeyGenerator.new(
178
- ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
179
- )
180
- else
181
- ActiveSupport::LegacyKeyGenerator.new(secrets.secret_token)
182
- end
176
+ @caching_key_generator ||= ActiveSupport::CachingKeyGenerator.new(
177
+ ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
178
+ )
183
179
  end
184
180
 
185
181
  # Returns a message verifier object.
@@ -209,12 +205,13 @@ module Rails
209
205
 
210
206
  # Convenience for loading config/foo.yml for the current Rails env.
211
207
  #
212
- # Example:
208
+ # Examples:
213
209
  #
214
210
  # # config/exception_notification.yml:
215
211
  # production:
216
212
  # url: http://127.0.0.1:8080
217
213
  # namespace: my_app_production
214
+ #
218
215
  # development:
219
216
  # url: http://localhost:3001
220
217
  # namespace: my_app_development
@@ -223,23 +220,40 @@ module Rails
223
220
  # Rails.application.configure do
224
221
  # config.middleware.use ExceptionNotifier, config_for(:exception_notification)
225
222
  # end
223
+ #
224
+ # # You can also store configurations in a shared section which will be
225
+ # # merged with the environment configuration
226
+ #
227
+ # # config/example.yml
228
+ # shared:
229
+ # foo:
230
+ # bar:
231
+ # baz: 1
232
+ #
233
+ # development:
234
+ # foo:
235
+ # bar:
236
+ # qux: 2
237
+ #
238
+ # # development environment
239
+ # Rails.application.config_for(:example)[:foo][:bar]
240
+ # # => { baz: 1, qux: 2 }
226
241
  def config_for(name, env: Rails.env)
227
- if name.is_a?(Pathname)
228
- yaml = name
229
- else
230
- yaml = Pathname.new("#{paths["config"].existent.first}/#{name}.yml")
231
- end
242
+ yaml = name.is_a?(Pathname) ? name : Pathname.new("#{paths["config"].existent.first}/#{name}.yml")
232
243
 
233
244
  if yaml.exist?
234
245
  require "erb"
235
- (YAML.load(ERB.new(yaml.read).result) || {})[env] || {}
246
+ all_configs = ActiveSupport::ConfigurationFile.parse(yaml).deep_symbolize_keys
247
+ config, shared = all_configs[env.to_sym], all_configs[:shared]
248
+
249
+ if config.is_a?(Hash)
250
+ ActiveSupport::OrderedOptions.new.update(shared&.deep_merge(config) || config)
251
+ else
252
+ config || shared
253
+ end
236
254
  else
237
255
  raise "Could not load configuration. No such file - #{yaml}"
238
256
  end
239
- rescue Psych::SyntaxError => e
240
- raise "YAML syntax error occurred while parsing #{yaml}. " \
241
- "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
242
- "Error: #{e.message}"
243
257
  end
244
258
 
245
259
  # Stores some of the Rails initial environment parameters which
@@ -249,7 +263,6 @@ module Rails
249
263
  super.merge(
250
264
  "action_dispatch.parameter_filter" => config.filter_parameters,
251
265
  "action_dispatch.redirect_filter" => config.filter_redirect,
252
- "action_dispatch.secret_token" => secrets.secret_token,
253
266
  "action_dispatch.secret_key_base" => secret_key_base,
254
267
  "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions,
255
268
  "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local,
@@ -267,9 +280,13 @@ module Rails
267
280
  "action_dispatch.cookies_serializer" => config.action_dispatch.cookies_serializer,
268
281
  "action_dispatch.cookies_digest" => config.action_dispatch.cookies_digest,
269
282
  "action_dispatch.cookies_rotations" => config.action_dispatch.cookies_rotations,
283
+ "action_dispatch.cookies_same_site_protection" => coerce_same_site_protection(config.action_dispatch.cookies_same_site_protection),
284
+ "action_dispatch.use_cookies_with_metadata" => config.action_dispatch.use_cookies_with_metadata,
270
285
  "action_dispatch.content_security_policy" => config.content_security_policy,
271
286
  "action_dispatch.content_security_policy_report_only" => config.content_security_policy_report_only,
272
- "action_dispatch.content_security_policy_nonce_generator" => config.content_security_policy_nonce_generator
287
+ "action_dispatch.content_security_policy_nonce_generator" => config.content_security_policy_nonce_generator,
288
+ "action_dispatch.content_security_policy_nonce_directives" => config.content_security_policy_nonce_directives,
289
+ "action_dispatch.permissions_policy" => config.permissions_policy,
273
290
  )
274
291
  end
275
292
  end
@@ -305,6 +322,12 @@ module Rails
305
322
  self.class.generators(&blk)
306
323
  end
307
324
 
325
+ # Sends any server called in the instance of a new application up
326
+ # to the +server+ method defined in Rails::Railtie.
327
+ def server(&blk)
328
+ self.class.server(&blk)
329
+ end
330
+
308
331
  # Sends the +isolate_namespace+ method up to the class method.
309
332
  def isolate_namespace(mod)
310
333
  self.class.isolate_namespace(mod)
@@ -348,7 +371,7 @@ module Rails
348
371
  files, dirs = config.watchable_files.dup, config.watchable_dirs.dup
349
372
 
350
373
  ActiveSupport::Dependencies.autoload_paths.each do |path|
351
- dirs[path.to_s] = [:rb]
374
+ File.file?(path) ? files << path.to_s : dirs[path.to_s] = [:rb]
352
375
  end
353
376
 
354
377
  [files, dirs]
@@ -373,24 +396,8 @@ module Rails
373
396
  @config ||= Application::Configuration.new(self.class.find_root(self.class.called_from))
374
397
  end
375
398
 
376
- def config=(configuration) #:nodoc:
377
- @config = configuration
378
- end
399
+ attr_writer :config
379
400
 
380
- # Returns secrets added to config/secrets.yml.
381
- #
382
- # Example:
383
- #
384
- # development:
385
- # secret_key_base: 836fa3665997a860728bcb9e9a1e704d427cfc920e79d847d79c8a9a907b9e965defa4154b2b86bdec6930adbe33f21364523a6f6ce363865724549fdfc08553
386
- # test:
387
- # secret_key_base: 5a37811464e7d378488b0f073e2193b093682e4e21f5d6f3ae0a4e1781e61a351fdc878a843424e81c73fb484a40d23f92c8dafac4870e74ede6e5e174423010
388
- # production:
389
- # secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
390
- # namespace: my_app_production
391
- #
392
- # +Rails.application.secrets.namespace+ returns +my_app_production+ in the
393
- # production environment.
394
401
  def secrets
395
402
  @secrets ||= begin
396
403
  secrets = ActiveSupport::OrderedOptions.new
@@ -400,34 +407,25 @@ module Rails
400
407
 
401
408
  # Fallback to config.secret_key_base if secrets.secret_key_base isn't set
402
409
  secrets.secret_key_base ||= config.secret_key_base
403
- # Fallback to config.secret_token if secrets.secret_token isn't set
404
- secrets.secret_token ||= config.secret_token
405
-
406
- if secrets.secret_token.present?
407
- ActiveSupport::Deprecation.warn(
408
- "`secrets.secret_token` is deprecated in favor of `secret_key_base` and will be removed in Rails 6.0."
409
- )
410
- end
411
410
 
412
411
  secrets
413
412
  end
414
413
  end
415
414
 
416
- def secrets=(secrets) #:nodoc:
417
- @secrets = secrets
418
- end
415
+ attr_writer :secrets, :credentials
419
416
 
420
417
  # The secret_key_base is used as the input secret to the application's key generator, which in turn
421
418
  # is used to create all MessageVerifiers/MessageEncryptors, including the ones that sign and encrypt cookies.
422
419
  #
423
- # In test and development, this is simply derived as a MD5 hash of the application's name.
420
+ # In development and test, this is randomly generated and stored in a
421
+ # temporary file in <tt>tmp/development_secret.txt</tt>.
424
422
  #
425
423
  # In all other environments, we look for it first in ENV["SECRET_KEY_BASE"],
426
424
  # then credentials.secret_key_base, and finally secrets.secret_key_base. For most applications,
427
425
  # the correct place to store it is in the encrypted credentials file.
428
426
  def secret_key_base
429
- if Rails.env.test? || Rails.env.development?
430
- Digest::MD5.hexdigest self.class.name
427
+ if Rails.env.development? || Rails.env.test?
428
+ secrets.secret_key_base ||= generate_development_secret
431
429
  else
432
430
  validate_secret_key_base(
433
431
  ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
@@ -438,13 +436,17 @@ module Rails
438
436
  # Decrypts the credentials hash as kept in +config/credentials.yml.enc+. This file is encrypted with
439
437
  # the Rails master key, which is either taken from <tt>ENV["RAILS_MASTER_KEY"]</tt> or from loading
440
438
  # +config/master.key+.
439
+ # If specific credentials file exists for current environment, it takes precedence, thus for +production+
440
+ # environment look first for +config/credentials/production.yml.enc+ with master key taken
441
+ # from <tt>ENV["RAILS_MASTER_KEY"]</tt> or from loading +config/credentials/production.key+.
442
+ # Default behavior can be overwritten by setting +config.credentials.content_path+ and +config.credentials.key_path+.
441
443
  def credentials
442
- @credentials ||= encrypted("config/credentials.yml.enc")
444
+ @credentials ||= encrypted(config.credentials.content_path, key_path: config.credentials.key_path)
443
445
  end
444
446
 
445
447
  # Shorthand to decrypt any encrypted configurations or files.
446
448
  #
447
- # For any file added with <tt>bin/rails encrypted:edit</tt> call +read+ to decrypt
449
+ # For any file added with <tt>rails encrypted:edit</tt> call +read+ to decrypt
448
450
  # the file with the master key.
449
451
  # The master key is either stored in +config/master.key+ or <tt>ENV["RAILS_MASTER_KEY"]</tt>.
450
452
  #
@@ -486,10 +488,6 @@ module Rails
486
488
  config.helpers_paths
487
489
  end
488
490
 
489
- console do
490
- require "pp"
491
- end
492
-
493
491
  console do
494
492
  unless ::Kernel.private_method_defined?(:y)
495
493
  require "psych/y"
@@ -506,16 +504,24 @@ module Rails
506
504
  ordered_railties.flatten - [self]
507
505
  end
508
506
 
509
- protected
507
+ # Eager loads the application code.
508
+ def eager_load!
509
+ if Rails.autoloaders.zeitwerk_enabled?
510
+ Rails.autoloaders.each(&:eager_load)
511
+ else
512
+ super
513
+ end
514
+ end
510
515
 
516
+ protected
511
517
  alias :build_middleware_stack :app
512
518
 
513
519
  def run_tasks_blocks(app) #:nodoc:
514
520
  railties.each { |r| r.run_tasks_blocks(app) }
515
521
  super
516
- require "rails/tasks"
522
+ load "rails/tasks.rb"
517
523
  task :environment do
518
- ActiveSupport.on_load(:before_initialize) { config.eager_load = false }
524
+ ActiveSupport.on_load(:before_initialize) { config.eager_load = config.rake_eager_load }
519
525
 
520
526
  require_environment!
521
527
  end
@@ -536,6 +542,11 @@ module Rails
536
542
  super
537
543
  end
538
544
 
545
+ def run_server_blocks(app) #:nodoc:
546
+ railties.each { |r| r.run_server_blocks(app) }
547
+ super
548
+ end
549
+
539
550
  # Returns the ordered railties for this application considering railties_order.
540
551
  def ordered_railties #:nodoc:
541
552
  @ordered_railties ||= begin
@@ -581,12 +592,27 @@ module Rails
581
592
  secret_key_base
582
593
  elsif secret_key_base
583
594
  raise ArgumentError, "`secret_key_base` for #{Rails.env} environment must be a type of String`"
584
- elsif secrets.secret_token.blank?
585
- raise ArgumentError, "Missing `secret_key_base` for '#{Rails.env}' environment, set this string with `rails credentials:edit`"
595
+ else
596
+ raise ArgumentError, "Missing `secret_key_base` for '#{Rails.env}' environment, set this string with `bin/rails credentials:edit`"
586
597
  end
587
598
  end
588
599
 
589
600
  private
601
+ def generate_development_secret
602
+ if secrets.secret_key_base.nil?
603
+ key_file = Rails.root.join("tmp/development_secret.txt")
604
+
605
+ if !File.exist?(key_file)
606
+ random_key = SecureRandom.hex(64)
607
+ FileUtils.mkdir_p(key_file.dirname)
608
+ File.binwrite(key_file, random_key)
609
+ end
610
+
611
+ secrets.secret_key_base = File.binread(key_file)
612
+ end
613
+
614
+ secrets.secret_key_base
615
+ end
590
616
 
591
617
  def build_request(env)
592
618
  req = super
@@ -598,5 +624,9 @@ module Rails
598
624
  def build_middleware
599
625
  config.app_middleware + super
600
626
  end
627
+
628
+ def coerce_same_site_protection(protection)
629
+ protection.respond_to?(:call) ? protection : proc { protection }
630
+ end
601
631
  end
602
632
  end
@@ -12,7 +12,6 @@ class Rails::ApplicationController < ActionController::Base # :nodoc:
12
12
  end
13
13
 
14
14
  private
15
-
16
15
  def require_local!
17
16
  unless local_request?
18
17
  render html: "<p>For security purposes, this information is only available to local requests.</p>".html_safe, status: :forbidden
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/dependencies/zeitwerk_integration"
4
+
5
+ module Rails
6
+ module Autoloaders # :nodoc:
7
+ class << self
8
+ include Enumerable
9
+
10
+ def main
11
+ if zeitwerk_enabled?
12
+ @main ||= Zeitwerk::Loader.new.tap do |loader|
13
+ loader.tag = "rails.main"
14
+ loader.inflector = ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector
15
+ end
16
+ end
17
+ end
18
+
19
+ def once
20
+ if zeitwerk_enabled?
21
+ @once ||= Zeitwerk::Loader.new.tap do |loader|
22
+ loader.tag = "rails.once"
23
+ loader.inflector = ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector
24
+ end
25
+ end
26
+ end
27
+
28
+ def each
29
+ if zeitwerk_enabled?
30
+ yield main
31
+ yield once
32
+ end
33
+ end
34
+
35
+ def logger=(logger)
36
+ each { |loader| loader.logger = logger }
37
+ end
38
+
39
+ def log!
40
+ each(&:log!)
41
+ end
42
+
43
+ def zeitwerk_enabled?
44
+ Rails.configuration.autoloader == :zeitwerk
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,34 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/backtrace_cleaner"
4
+ require "active_support/core_ext/string/access"
4
5
 
5
6
  module Rails
6
7
  class BacktraceCleaner < ActiveSupport::BacktraceCleaner
7
- APP_DIRS_PATTERN = /^\/?(app|config|lib|test|\(\w*\))/
8
- RENDER_TEMPLATE_PATTERN = /:in `_render_template_\w*'/
9
- EMPTY_STRING = "".freeze
10
- SLASH = "/".freeze
11
- DOT_SLASH = "./".freeze
8
+ APP_DIRS_PATTERN = /\A(?:\.\/)?(?:app|config|lib|test|\(\w*\))/
9
+ RENDER_TEMPLATE_PATTERN = /:in `.*_\w+_{2,3}\d+_\d+'/
12
10
 
13
11
  def initialize
14
12
  super
15
- @root = "#{Rails.root}/".freeze
16
- add_filter { |line| line.sub(@root, EMPTY_STRING) }
17
- add_filter { |line| line.sub(RENDER_TEMPLATE_PATTERN, EMPTY_STRING) }
18
- add_filter { |line| line.sub(DOT_SLASH, SLASH) } # for tests
19
-
20
- add_gem_filters
13
+ @root = "#{Rails.root}/"
14
+ add_filter do |line|
15
+ line.start_with?(@root) ? line.from(@root.size) : line
16
+ end
17
+ add_filter do |line|
18
+ if RENDER_TEMPLATE_PATTERN.match?(line)
19
+ line.sub(RENDER_TEMPLATE_PATTERN, "")
20
+ else
21
+ line
22
+ end
23
+ end
21
24
  add_silencer { |line| !APP_DIRS_PATTERN.match?(line) }
22
25
  end
23
-
24
- private
25
- def add_gem_filters
26
- gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
27
- return if gems_paths.empty?
28
-
29
- gems_regexp = %r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w.]+)/(.*)}
30
- gems_result = '\2 (\3) \4'.freeze
31
- add_filter { |line| line.sub(gems_regexp, gems_result) }
32
- end
33
26
  end
34
27
  end
@@ -8,6 +8,8 @@ class CodeStatistics #:nodoc:
8
8
  "Helper tests",
9
9
  "Model tests",
10
10
  "Mailer tests",
11
+ "Mailbox tests",
12
+ "Channel tests",
11
13
  "Job tests",
12
14
  "Integration tests",
13
15
  "System tests"]
@@ -38,15 +40,15 @@ class CodeStatistics #:nodoc:
38
40
  Hash[@pairs.map { |pair| [pair.first, calculate_directory_statistics(pair.last)] }]
39
41
  end
40
42
 
41
- def calculate_directory_statistics(directory, pattern = /^(?!\.).*?\.(rb|js|coffee|rake)$/)
43
+ def calculate_directory_statistics(directory, pattern = /^(?!\.).*?\.(rb|js|ts|coffee|rake)$/)
42
44
  stats = CodeStatisticsCalculator.new
43
45
 
44
46
  Dir.foreach(directory) do |file_name|
45
47
  path = "#{directory}/#{file_name}"
46
48
 
47
- if File.directory?(path) && (/^\./ !~ file_name)
49
+ if File.directory?(path) && !file_name.start_with?(".")
48
50
  stats.add(calculate_directory_statistics(path, pattern))
49
- elsif file_name =~ pattern
51
+ elsif file_name&.match?(pattern)
50
52
  stats.add_by_file_path(path)
51
53
  end
52
54
  end
@@ -73,7 +75,7 @@ class CodeStatistics #:nodoc:
73
75
  end
74
76
 
75
77
  def width_for(label)
76
- [@statistics.values.sum { |s| s.send(label) }.to_s.size, HEADERS[label].length].max
78
+ [@statistics.values.sum { |s| s.public_send(label) }.to_s.size, HEADERS[label].length].max
77
79
  end
78
80
 
79
81
  def print_header
@@ -95,8 +97,8 @@ class CodeStatistics #:nodoc:
95
97
  end
96
98
 
97
99
  def print_line(name, statistics)
98
- m_over_c = (statistics.methods / statistics.classes) rescue m_over_c = 0
99
- loc_over_m = (statistics.code_lines / statistics.methods) - 2 rescue loc_over_m = 0
100
+ m_over_c = (statistics.methods / statistics.classes) rescue 0
101
+ loc_over_m = (statistics.code_lines / statistics.methods) - 2 rescue 0
100
102
 
101
103
  print "| #{name.ljust(20)} "
102
104
  HEADERS.each_key do |k|
@@ -58,20 +58,20 @@ class CodeStatisticsCalculator #:nodoc:
58
58
  @lines += 1
59
59
 
60
60
  if comment_started
61
- if patterns[:end_block_comment] && line =~ patterns[:end_block_comment]
61
+ if patterns[:end_block_comment] && patterns[:end_block_comment].match?(line)
62
62
  comment_started = false
63
63
  end
64
64
  next
65
65
  else
66
- if patterns[:begin_block_comment] && line =~ patterns[:begin_block_comment]
66
+ if patterns[:begin_block_comment] && patterns[:begin_block_comment].match?(line)
67
67
  comment_started = true
68
68
  next
69
69
  end
70
70
  end
71
71
 
72
- @classes += 1 if patterns[:class] && line =~ patterns[:class]
73
- @methods += 1 if patterns[:method] && line =~ patterns[:method]
74
- if line !~ /^\s*$/ && (patterns[:line_comment].nil? || line !~ patterns[:line_comment])
72
+ @classes += 1 if patterns[:class] && patterns[:class].match?(line)
73
+ @methods += 1 if patterns[:method] && patterns[:method].match?(line)
74
+ if !line.match?(/^\s*$/) && (patterns[:line_comment].nil? || !line.match?(patterns[:line_comment]))
75
75
  @code_lines += 1
76
76
  end
77
77
  end
@@ -82,7 +82,7 @@ class CodeStatisticsCalculator #:nodoc:
82
82
  if file_path.end_with? "_test.rb"
83
83
  :minitest
84
84
  else
85
- File.extname(file_path).sub(/\A\./, "").downcase.to_sym
85
+ File.extname(file_path).delete_prefix(".").downcase.to_sym
86
86
  end
87
87
  end
88
88
  end