railties 7.0.8.7 → 7.1.5.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 (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +723 -215
  3. data/MIT-LICENSE +1 -1
  4. data/RDOC_MAIN.md +99 -0
  5. data/README.rdoc +4 -4
  6. data/lib/minitest/rails_plugin.rb +63 -0
  7. data/lib/rails/api/task.rb +35 -4
  8. data/lib/rails/app_updater.rb +14 -2
  9. data/lib/rails/application/bootstrap.rb +23 -4
  10. data/lib/rails/application/configuration.rb +190 -69
  11. data/lib/rails/application/default_middleware_stack.rb +8 -2
  12. data/lib/rails/application/dummy_config.rb +19 -0
  13. data/lib/rails/application/finisher.rb +43 -33
  14. data/lib/rails/application.rb +141 -33
  15. data/lib/rails/backtrace_cleaner.rb +5 -3
  16. data/lib/rails/cli.rb +5 -2
  17. data/lib/rails/command/actions.rb +10 -12
  18. data/lib/rails/command/base.rb +55 -53
  19. data/lib/rails/command/environment_argument.rb +32 -16
  20. data/lib/rails/command/helpers/editor.rb +17 -12
  21. data/lib/rails/command.rb +84 -33
  22. data/lib/rails/commands/about/about_command.rb +14 -0
  23. data/lib/rails/commands/application/application_command.rb +2 -0
  24. data/lib/rails/commands/console/console_command.rb +14 -14
  25. data/lib/rails/commands/credentials/USAGE +53 -55
  26. data/lib/rails/commands/credentials/credentials_command/diffing.rb +5 -3
  27. data/lib/rails/commands/credentials/credentials_command.rb +64 -70
  28. data/lib/rails/commands/db/system/change/change_command.rb +2 -1
  29. data/lib/rails/commands/dbconsole/dbconsole_command.rb +25 -115
  30. data/lib/rails/commands/destroy/destroy_command.rb +3 -2
  31. data/lib/rails/commands/dev/dev_command.rb +1 -6
  32. data/lib/rails/commands/encrypted/USAGE +15 -20
  33. data/lib/rails/commands/encrypted/encrypted_command.rb +46 -35
  34. data/lib/rails/commands/gem_help/USAGE +16 -0
  35. data/lib/rails/commands/gem_help/gem_help_command.rb +13 -0
  36. data/lib/rails/commands/generate/generate_command.rb +2 -2
  37. data/lib/rails/commands/help/USAGE +13 -13
  38. data/lib/rails/commands/help/help_command.rb +21 -2
  39. data/lib/rails/commands/initializers/initializers_command.rb +1 -4
  40. data/lib/rails/commands/middleware/middleware_command.rb +17 -0
  41. data/lib/rails/commands/new/new_command.rb +2 -0
  42. data/lib/rails/commands/notes/notes_command.rb +2 -1
  43. data/lib/rails/commands/plugin/plugin_command.rb +2 -0
  44. data/lib/rails/commands/rake/rake_command.rb +25 -22
  45. data/lib/rails/commands/restart/restart_command.rb +14 -0
  46. data/lib/rails/commands/routes/routes_command.rb +13 -1
  47. data/lib/rails/commands/runner/USAGE +14 -12
  48. data/lib/rails/commands/runner/runner_command.rb +32 -20
  49. data/lib/rails/commands/secret/secret_command.rb +13 -0
  50. data/lib/rails/commands/secrets/USAGE +44 -49
  51. data/lib/rails/commands/secrets/secrets_command.rb +20 -38
  52. data/lib/rails/commands/server/server_command.rb +33 -32
  53. data/lib/rails/commands/test/USAGE +14 -0
  54. data/lib/rails/commands/test/test_command.rb +56 -14
  55. data/lib/rails/commands/unused_routes/unused_routes_command.rb +75 -0
  56. data/lib/rails/commands/version/version_command.rb +1 -0
  57. data/lib/rails/configuration.rb +5 -5
  58. data/lib/rails/console/app.rb +1 -4
  59. data/lib/rails/deprecator.rb +7 -0
  60. data/lib/rails/engine/configuration.rb +50 -6
  61. data/lib/rails/engine.rb +49 -21
  62. data/lib/rails/gem_version.rb +4 -4
  63. data/lib/rails/generators/actions.rb +6 -15
  64. data/lib/rails/generators/active_model.rb +28 -14
  65. data/lib/rails/generators/app_base.rb +355 -82
  66. data/lib/rails/generators/app_name.rb +3 -14
  67. data/lib/rails/generators/base.rb +17 -9
  68. data/lib/rails/generators/database.rb +40 -2
  69. data/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt +1 -1
  70. data/lib/rails/generators/generated_attribute.rb +12 -0
  71. data/lib/rails/generators/migration.rb +4 -5
  72. data/lib/rails/generators/model_helpers.rb +2 -1
  73. data/lib/rails/generators/rails/app/USAGE +22 -6
  74. data/lib/rails/generators/rails/app/app_generator.rb +85 -64
  75. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +103 -0
  76. data/lib/rails/generators/rails/app/templates/Gemfile.tt +9 -11
  77. data/lib/rails/generators/rails/app/templates/app/views/layouts/mailer.html.erb.tt +1 -1
  78. data/lib/rails/generators/rails/app/templates/bin/setup.tt +10 -1
  79. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +6 -17
  80. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +4 -4
  81. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +3 -3
  82. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +4 -6
  83. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +3 -3
  84. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +59 -0
  85. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +12 -2
  86. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +32 -28
  87. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +13 -9
  88. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +2 -0
  89. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +2 -2
  90. data/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt +1 -1
  91. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +3 -3
  92. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_1.rb.tt +280 -0
  93. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +11 -9
  94. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +11 -13
  95. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +21 -20
  96. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +5 -1
  97. data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +6 -4
  98. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +10 -0
  99. data/lib/rails/generators/rails/app/templates/dockerignore.tt +43 -0
  100. data/lib/rails/generators/rails/app/templates/gitignore.tt +4 -8
  101. data/lib/rails/generators/rails/app/templates/node-version.tt +1 -0
  102. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +10 -8
  103. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +9 -7
  104. data/lib/rails/generators/rails/application_record/application_record_generator.rb +4 -0
  105. data/lib/rails/generators/rails/benchmark/benchmark_generator.rb +2 -1
  106. data/lib/rails/generators/rails/controller/USAGE +12 -4
  107. data/lib/rails/generators/rails/controller/controller_generator.rb +5 -0
  108. data/lib/rails/generators/rails/controller/templates/controller.rb.tt +1 -1
  109. data/lib/rails/generators/rails/credentials/credentials_generator.rb +29 -24
  110. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +8 -0
  111. data/lib/rails/generators/rails/db/system/change/change_generator.rb +30 -0
  112. data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +1 -2
  113. data/lib/rails/generators/rails/migration/USAGE +21 -11
  114. data/lib/rails/generators/rails/model/model_generator.rb +4 -0
  115. data/lib/rails/generators/rails/plugin/USAGE +17 -6
  116. data/lib/rails/generators/rails/plugin/plugin_generator.rb +5 -15
  117. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +2 -2
  118. data/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt +1 -1
  119. data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +1 -17
  120. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +0 -2
  121. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +4 -4
  122. data/lib/rails/generators/rails/resource/resource_generator.rb +6 -0
  123. data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +2 -1
  124. data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +1 -1
  125. data/lib/rails/generators/test_case.rb +2 -2
  126. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +1 -1
  127. data/lib/rails/generators/testing/{behaviour.rb → behavior.rb} +4 -1
  128. data/lib/rails/generators.rb +6 -14
  129. data/lib/rails/health_controller.rb +55 -0
  130. data/lib/rails/info.rb +1 -1
  131. data/lib/rails/info_controller.rb +33 -11
  132. data/lib/rails/mailers_controller.rb +15 -5
  133. data/lib/rails/paths.rb +13 -10
  134. data/lib/rails/rack/logger.rb +15 -12
  135. data/lib/rails/rackup/server.rb +15 -0
  136. data/lib/rails/railtie/configuration.rb +14 -1
  137. data/lib/rails/railtie.rb +31 -31
  138. data/lib/rails/ruby_version_check.rb +2 -0
  139. data/lib/rails/source_annotation_extractor.rb +67 -18
  140. data/lib/rails/tasks/engine.rake +8 -8
  141. data/lib/rails/tasks/framework.rake +4 -10
  142. data/lib/rails/tasks/log.rake +1 -1
  143. data/lib/rails/tasks/misc.rake +3 -14
  144. data/lib/rails/tasks/statistics.rake +5 -4
  145. data/lib/rails/tasks/tmp.rake +5 -5
  146. data/lib/rails/tasks/zeitwerk.rake +15 -35
  147. data/lib/rails/tasks.rb +0 -2
  148. data/lib/rails/templates/rails/mailers/email.html.erb +32 -0
  149. data/lib/rails/templates/rails/mailers/index.html.erb +14 -7
  150. data/lib/rails/templates/rails/mailers/mailer.html.erb +11 -5
  151. data/lib/rails/templates/rails/welcome/index.html.erb +1 -0
  152. data/lib/rails/test_help.rb +9 -14
  153. data/lib/rails/test_unit/line_filtering.rb +1 -1
  154. data/lib/rails/test_unit/reporter.rb +6 -2
  155. data/lib/rails/test_unit/runner.rb +36 -18
  156. data/lib/rails/test_unit/test_parser.rb +88 -0
  157. data/lib/rails/test_unit/testing.rake +13 -33
  158. data/lib/rails/testing/maintain_test_schema.rb +16 -0
  159. data/lib/rails/version.rb +1 -1
  160. data/lib/rails/zeitwerk_checker.rb +15 -0
  161. data/lib/rails.rb +15 -15
  162. metadata +64 -27
  163. data/RDOC_MAIN.rdoc +0 -97
  164. data/lib/rails/application/dummy_erb_compiler.rb +0 -18
  165. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt +0 -143
  166. data/lib/rails/generators/rails/model/USAGE +0 -113
  167. data/lib/rails/tasks/middleware.rake +0 -9
  168. data/lib/rails/tasks/restart.rake +0 -9
@@ -4,7 +4,8 @@ require "yaml"
4
4
  require "active_support/core_ext/hash/keys"
5
5
  require "active_support/core_ext/object/blank"
6
6
  require "active_support/key_generator"
7
- require "active_support/message_verifier"
7
+ require "active_support/message_verifiers"
8
+ require "active_support/deprecation"
8
9
  require "active_support/encrypted_configuration"
9
10
  require "active_support/hash_with_indifferent_access"
10
11
  require "active_support/configuration_file"
@@ -26,7 +27,7 @@ module Rails
26
27
  #
27
28
  # Besides providing the same configuration as Rails::Engine and Rails::Railtie,
28
29
  # the application object has several specific configurations, for example
29
- # +cache_classes+, +consider_all_requests_local+, +filter_parameters+,
30
+ # +enable_reloading+, +consider_all_requests_local+, +filter_parameters+,
30
31
  # +logger+, and so forth.
31
32
  #
32
33
  # Check Rails::Application::Configuration to see them all.
@@ -70,6 +71,8 @@ module Rails
70
71
  def inherited(base)
71
72
  super
72
73
  Rails.app_class = base
74
+ # lib has to be added to $LOAD_PATH unconditionally, even if it's in the
75
+ # autoload paths and config.add_autoload_paths_to_load_path is false.
73
76
  add_lib_to_load_path!(find_root(base.called_from))
74
77
  ActiveSupport.run_load_hooks(:before_configuration, base)
75
78
  end
@@ -111,7 +114,9 @@ module Rails
111
114
  @app_env_config = nil
112
115
  @ordered_railties = nil
113
116
  @railties = nil
114
- @message_verifiers = {}
117
+ @key_generators = {}
118
+ @message_verifiers = nil
119
+ @deprecators = nil
115
120
  @ran_load_hooks = false
116
121
 
117
122
  @executor = Class.new(ActiveSupport::Executor)
@@ -149,15 +154,53 @@ module Rails
149
154
  routes_reloader.reload!
150
155
  end
151
156
 
152
- # Returns the application's KeyGenerator
153
- def key_generator
157
+ # Returns a key generator (ActiveSupport::CachingKeyGenerator) for a
158
+ # specified +secret_key_base+. The return value is memoized, so additional
159
+ # calls with the same +secret_key_base+ will return the same key generator
160
+ # instance.
161
+ def key_generator(secret_key_base = self.secret_key_base)
154
162
  # number of iterations selected based on consultation with the google security
155
163
  # team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220
156
- @caching_key_generator ||= ActiveSupport::CachingKeyGenerator.new(
164
+ @key_generators[secret_key_base] ||= ActiveSupport::CachingKeyGenerator.new(
157
165
  ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
158
166
  )
159
167
  end
160
168
 
169
+ # Returns a message verifier factory (ActiveSupport::MessageVerifiers). This
170
+ # factory can be used as a central point to configure and create message
171
+ # verifiers (ActiveSupport::MessageVerifier) for your application.
172
+ #
173
+ # By default, message verifiers created by this factory will generate
174
+ # messages using the default ActiveSupport::MessageVerifier options. You can
175
+ # override these options with a combination of
176
+ # ActiveSupport::MessageVerifiers#clear_rotations and
177
+ # ActiveSupport::MessageVerifiers#rotate. However, this must be done prior
178
+ # to building any message verifier instances. For example, in a
179
+ # +before_initialize+ block:
180
+ #
181
+ # # Use `url_safe: true` when generating messages
182
+ # config.before_initialize do |app|
183
+ # app.message_verifiers.clear_rotations
184
+ # app.message_verifiers.rotate(url_safe: true)
185
+ # end
186
+ #
187
+ # Message verifiers created by this factory will always use a secret derived
188
+ # from #secret_key_base when generating messages. +clear_rotations+ will not
189
+ # affect this behavior. However, older +secret_key_base+ values can be
190
+ # rotated for verifying messages:
191
+ #
192
+ # # Fall back to old `secret_key_base` when verifying messages
193
+ # config.before_initialize do |app|
194
+ # app.message_verifiers.rotate(secret_key_base: "old secret_key_base")
195
+ # end
196
+ #
197
+ def message_verifiers
198
+ @message_verifiers ||=
199
+ ActiveSupport::MessageVerifiers.new do |salt, secret_key_base: self.secret_key_base|
200
+ key_generator(secret_key_base).generate_key(salt)
201
+ end.rotate_defaults
202
+ end
203
+
161
204
  # Returns a message verifier object.
162
205
  #
163
206
  # This verifier can be used to generate and verify signed messages in the application.
@@ -177,15 +220,21 @@ module Rails
177
220
  #
178
221
  # See the ActiveSupport::MessageVerifier documentation for more information.
179
222
  def message_verifier(verifier_name)
180
- @message_verifiers[verifier_name] ||= begin
181
- secret = key_generator.generate_key(verifier_name.to_s)
182
- ActiveSupport::MessageVerifier.new(secret)
223
+ message_verifiers[verifier_name]
224
+ end
225
+
226
+ # A managed collection of deprecators (ActiveSupport::Deprecation::Deprecators).
227
+ # The collection's configuration methods affect all deprecators in the
228
+ # collection. Additionally, the collection's +silence+ method silences all
229
+ # deprecators in the collection for the duration of a given block.
230
+ def deprecators
231
+ @deprecators ||= ActiveSupport::Deprecation::Deprecators.new.tap do |deprecators|
232
+ deprecators[:railties] = Rails.deprecator
183
233
  end
184
234
  end
185
235
 
186
- # Convenience for loading config/foo.yml for the current Rails env.
187
- #
188
- # Examples:
236
+ # Convenience for loading config/foo.yml for the current \Rails env.
237
+ # Example:
189
238
  #
190
239
  # # config/exception_notification.yml:
191
240
  # production:
@@ -196,13 +245,15 @@ module Rails
196
245
  # url: http://localhost:3001
197
246
  # namespace: my_app_development
198
247
  #
248
+ # <code></code>
249
+ #
199
250
  # # config/environments/production.rb
200
251
  # Rails.application.configure do
201
252
  # config.middleware.use ExceptionNotifier, config_for(:exception_notification)
202
253
  # end
203
254
  #
204
- # # You can also store configurations in a shared section which will be
205
- # # merged with the environment configuration
255
+ # You can also store configurations in a shared section which will be merged
256
+ # with the environment configuration
206
257
  #
207
258
  # # config/example.yml
208
259
  # shared:
@@ -215,6 +266,8 @@ module Rails
215
266
  # bar:
216
267
  # qux: 2
217
268
  #
269
+ # <code></code>
270
+ #
218
271
  # # development environment
219
272
  # Rails.application.config_for(:example)[:foo][:bar]
220
273
  # # => { baz: 1, qux: 2 }
@@ -245,16 +298,17 @@ module Rails
245
298
  end
246
299
  end
247
300
 
248
- # Stores some of the Rails initial environment parameters which
301
+ # Stores some of the \Rails initial environment parameters which
249
302
  # will be used by middlewares and engines to configure themselves.
250
303
  def env_config
251
304
  @app_env_config ||= super.merge(
252
- "action_dispatch.parameter_filter" => config.filter_parameters,
305
+ "action_dispatch.parameter_filter" => filter_parameters,
253
306
  "action_dispatch.redirect_filter" => config.filter_redirect,
254
307
  "action_dispatch.secret_key_base" => secret_key_base,
255
308
  "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions,
256
309
  "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local,
257
310
  "action_dispatch.log_rescued_responses" => config.action_dispatch.log_rescued_responses,
311
+ "action_dispatch.debug_exception_log_level" => ActiveSupport::Logger.const_get(config.action_dispatch.debug_exception_log_level.to_s.upcase),
258
312
  "action_dispatch.logger" => Rails.logger,
259
313
  "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner,
260
314
  "action_dispatch.key_generator" => key_generator,
@@ -337,7 +391,7 @@ module Rails
337
391
  # Rails application, you will need to add lib to $LOAD_PATH on your own in case
338
392
  # you need to load files in lib/ during the application configuration as well.
339
393
  def self.add_lib_to_load_path!(root) # :nodoc:
340
- path = File.join root, "lib"
394
+ path = File.join(root, "lib")
341
395
  if File.exist?(path) && !$LOAD_PATH.include?(path)
342
396
  $LOAD_PATH.unshift(path)
343
397
  end
@@ -387,6 +441,9 @@ module Rails
387
441
  attr_writer :config
388
442
 
389
443
  def secrets
444
+ Rails.deprecator.warn(<<~MSG.squish)
445
+ `Rails.application.secrets` is deprecated in favor of `Rails.application.credentials` and will be removed in Rails 7.2.
446
+ MSG
390
447
  @secrets ||= begin
391
448
  secrets = ActiveSupport::OrderedOptions.new
392
449
  files = config.paths["config/secrets"].existent
@@ -407,19 +464,42 @@ module Rails
407
464
  # including the ones that sign and encrypt cookies.
408
465
  #
409
466
  # In development and test, this is randomly generated and stored in a
410
- # temporary file in <tt>tmp/development_secret.txt</tt>.
467
+ # temporary file in <tt>tmp/local_secret.txt</tt>.
468
+ #
469
+ # You can also set <tt>ENV["SECRET_KEY_BASE_DUMMY"]</tt> to trigger the use of a randomly generated
470
+ # secret_key_base that's stored in a temporary file. This is useful when precompiling assets for
471
+ # production as part of a build step that otherwise does not need access to the production secrets.
472
+ #
473
+ # Dockerfile example: <tt>RUN SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile</tt>.
411
474
  #
412
475
  # In all other environments, we look for it first in <tt>ENV["SECRET_KEY_BASE"]</tt>,
413
476
  # then +credentials.secret_key_base+, and finally +secrets.secret_key_base+. For most applications,
414
477
  # the correct place to store it is in the encrypted credentials file.
415
478
  def secret_key_base
416
- if Rails.env.development? || Rails.env.test?
417
- secrets.secret_key_base ||= generate_development_secret
418
- else
419
- validate_secret_key_base(
420
- ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
421
- )
422
- end
479
+ config.secret_key_base ||=
480
+ if ENV["SECRET_KEY_BASE_DUMMY"]
481
+ generate_local_secret
482
+ else
483
+ validate_secret_key_base(
484
+ ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || begin
485
+ secret_skb = secrets_secret_key_base
486
+
487
+ if secret_skb && secret_skb.equal?(config.secret_key_base)
488
+ config.secret_key_base
489
+ elsif secret_skb
490
+ Rails.deprecator.warn(<<~MSG.squish)
491
+ Your `secret_key_base` is configured in `Rails.application.secrets`,
492
+ which is deprecated in favor of `Rails.application.credentials` and
493
+ will be removed in Rails 7.2.
494
+ MSG
495
+
496
+ secret_skb
497
+ elsif Rails.env.local?
498
+ generate_local_secret
499
+ end
500
+ end
501
+ )
502
+ end
423
503
  end
424
504
 
425
505
  # Returns an ActiveSupport::EncryptedConfiguration instance for the
@@ -488,6 +568,11 @@ module Rails
488
568
  ordered_railties.flatten - [self]
489
569
  end
490
570
 
571
+ def load_generators(app = self) # :nodoc:
572
+ app.ensure_generator_templates_added
573
+ super
574
+ end
575
+
491
576
  # Eager loads the application code.
492
577
  def eager_load!
493
578
  Rails.autoloaders.each(&:eager_load)
@@ -577,21 +662,35 @@ module Rails
577
662
  end
578
663
  end
579
664
 
580
- private
581
- def generate_development_secret
582
- if secrets.secret_key_base.nil?
583
- key_file = Rails.root.join("tmp/development_secret.txt")
665
+ def ensure_generator_templates_added
666
+ configured_paths = config.generators.templates
667
+ configured_paths.unshift(*(paths["lib/templates"].existent - configured_paths))
668
+ end
584
669
 
585
- if !File.exist?(key_file)
670
+ private
671
+ def generate_local_secret
672
+ if config.secret_key_base.nil?
673
+ key_file = Rails.root.join("tmp/local_secret.txt")
674
+
675
+ if File.exist?(key_file)
676
+ config.secret_key_base = File.binread(key_file)
677
+ elsif secrets_secret_key_base
678
+ config.secret_key_base = secrets_secret_key_base
679
+ else
586
680
  random_key = SecureRandom.hex(64)
587
681
  FileUtils.mkdir_p(key_file.dirname)
588
682
  File.binwrite(key_file, random_key)
683
+ config.secret_key_base = File.binread(key_file)
589
684
  end
590
-
591
- secrets.secret_key_base = File.binread(key_file)
592
685
  end
593
686
 
594
- secrets.secret_key_base
687
+ config.secret_key_base
688
+ end
689
+
690
+ def secrets_secret_key_base
691
+ Rails.deprecator.silence do
692
+ secrets.secret_key_base
693
+ end
595
694
  end
596
695
 
597
696
  def build_request(env)
@@ -608,5 +707,14 @@ module Rails
608
707
  def coerce_same_site_protection(protection)
609
708
  protection.respond_to?(:call) ? protection : proc { protection }
610
709
  end
710
+
711
+ def filter_parameters
712
+ if config.precompile_filter_parameters
713
+ config.filter_parameters.replace(
714
+ ActiveSupport::ParameterFilter.precompile_filters(config.filter_parameters)
715
+ )
716
+ end
717
+ config.filter_parameters
718
+ end
611
719
  end
612
720
  end
@@ -4,15 +4,17 @@ require "active_support/backtrace_cleaner"
4
4
  require "active_support/core_ext/string/access"
5
5
 
6
6
  module Rails
7
- class BacktraceCleaner < ActiveSupport::BacktraceCleaner
7
+ class BacktraceCleaner < ActiveSupport::BacktraceCleaner # :nodoc:
8
8
  APP_DIRS_PATTERN = /\A(?:\.\/)?(?:app|config|lib|test|\(\w*\))/
9
9
  RENDER_TEMPLATE_PATTERN = /:in `.*_\w+_{2,3}\d+_\d+'/
10
10
 
11
11
  def initialize
12
12
  super
13
- @root = "#{Rails.root}/"
14
13
  add_filter do |line|
15
- line.start_with?(@root) ? line.from(@root.size) : line
14
+ # We may be called before Rails.root is assigned.
15
+ # When that happens we fallback to not truncating.
16
+ @root ||= Rails.root && "#{Rails.root}/"
17
+ @root && line.start_with?(@root) ? line.from(@root.size) : line
16
18
  end
17
19
  add_filter do |line|
18
20
  if RENDER_TEMPLATE_PATTERN.match?(line)
data/lib/rails/cli.rb CHANGED
@@ -10,8 +10,11 @@ require "rails/ruby_version_check"
10
10
  Signal.trap("INT") { puts; exit(1) }
11
11
 
12
12
  require "rails/command"
13
-
14
- if ARGV.first == "plugin"
13
+ case ARGV.first
14
+ when Rails::Command::HELP_MAPPINGS, "help", nil
15
+ ARGV.shift
16
+ Rails::Command.invoke :gem_help, ARGV
17
+ when "plugin"
15
18
  ARGV.shift
16
19
  Rails::Command.invoke :plugin, ARGV
17
20
  else
@@ -10,23 +10,21 @@ module Rails
10
10
  Dir.chdir(File.expand_path("../..", APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
11
11
  end
12
12
 
13
- def require_application_and_environment!
14
- require_application!
15
- require_environment!
16
- end
17
-
18
13
  def require_application!
19
14
  require ENGINE_PATH if defined?(ENGINE_PATH)
15
+ require APP_PATH if defined?(APP_PATH)
16
+ end
20
17
 
21
- if defined?(APP_PATH)
22
- require APP_PATH
23
- end
18
+ def boot_application!
19
+ require_application!
20
+ Rails.application.require_environment! if defined?(APP_PATH)
24
21
  end
25
22
 
26
- def require_environment!
27
- if defined?(APP_PATH)
28
- Rails.application.require_environment!
29
- end
23
+ def load_environment_config!
24
+ require_application!
25
+ # Only run initializers that are in the :all group, which includes the
26
+ # :load_environment_config initializer.
27
+ Rails.application.initialize!(:_) if defined?(APP_PATH)
30
28
  end
31
29
 
32
30
  if defined?(ENGINE_PATH)
@@ -3,7 +3,8 @@
3
3
  require "thor"
4
4
  require "erb"
5
5
 
6
- require "active_support/core_ext/string/filters"
6
+ require "active_support/core_ext/class/attribute"
7
+ require "active_support/core_ext/module/delegation"
7
8
  require "active_support/core_ext/string/inflections"
8
9
 
9
10
  require "rails/command/actions"
@@ -14,32 +15,16 @@ module Rails
14
15
  class Error < Thor::Error # :nodoc:
15
16
  end
16
17
 
17
- class CorrectableError < Error # :nodoc:
18
- attr_reader :key, :options
19
-
20
- def initialize(message, key, options)
21
- @key = key
22
- @options = options
23
- super(message)
24
- end
25
-
26
- if defined?(DidYouMean::SpellChecker) && defined?(DidYouMean::Correctable)
27
- include DidYouMean::Correctable
28
-
29
- def corrections
30
- @corrections ||= DidYouMean::SpellChecker.new(dictionary: options).correct(key)
31
- end
32
- end
33
- end
34
-
35
18
  include Actions
36
19
 
20
+ class_attribute :bin, instance_accessor: false, default: "bin/rails"
21
+
37
22
  class << self
38
23
  def exit_on_failure? # :nodoc:
39
24
  false
40
25
  end
41
26
 
42
- # Returns true when the app is a Rails engine.
27
+ # Returns true when the app is a \Rails engine.
43
28
  def engine?
44
29
  defined?(ENGINE_ROOT)
45
30
  end
@@ -50,7 +35,7 @@ module Rails
50
35
  if usage
51
36
  super
52
37
  else
53
- @desc ||= ERB.new(File.read(usage_path), trim_mode: "-").result(binding) if usage_path
38
+ class_usage
54
39
  end
55
40
  end
56
41
 
@@ -81,23 +66,38 @@ module Rails
81
66
 
82
67
  def perform(command, args, config) # :nodoc:
83
68
  if Rails::Command::HELP_MAPPINGS.include?(args.first)
84
- command, args = "help", []
69
+ command, args = "help", [command]
70
+ args.clear if instance_method(:help).arity.zero?
85
71
  end
86
72
 
87
73
  dispatch(command, args.dup, nil, config)
88
74
  end
89
75
 
90
76
  def printing_commands
91
- namespaced_commands
77
+ commands.filter_map do |name, command|
78
+ [namespaced_name(name), command.description] unless command.hidden?
79
+ end
92
80
  end
93
81
 
94
- def executable
95
- "rails #{command_name}"
82
+ def executable(command_name = self.command_name)
83
+ "#{bin} #{namespaced_name(command_name)}"
96
84
  end
97
85
 
98
- # Use Rails' default banner.
99
- def banner(*)
100
- "#{executable} #{arguments.map(&:usage).join(' ')} [options]".squish
86
+ def banner(command = nil, *)
87
+ if command
88
+ # Similar to Thor's banner, but show the namespace (minus the
89
+ # "rails:" prefix), and show the command's declared bin instead of
90
+ # the command runner.
91
+ command.formatted_usage(self).gsub(/^#{namespace}:(\w+)/) { executable($1) }
92
+ else
93
+ executable
94
+ end
95
+ end
96
+
97
+ # Override Thor's class-level help to also show the USAGE.
98
+ def help(shell, *) # :nodoc:
99
+ super
100
+ shell.say class_usage if class_usage
101
101
  end
102
102
 
103
103
  # Sets the base_name taking into account the current class namespace.
@@ -119,12 +119,16 @@ module Rails
119
119
  end
120
120
  end
121
121
 
122
+ def class_usage # :nodoc:
123
+ if usage_path
124
+ @class_usage ||= ERB.new(File.read(usage_path), trim_mode: "-").result(binding)
125
+ end
126
+ end
127
+
122
128
  # Path to lookup a USAGE description in a file.
123
129
  def usage_path
124
- if default_command_root
125
- path = File.join(default_command_root, "USAGE")
126
- path if File.exist?(path)
127
- end
130
+ @usage_path = resolve_path("USAGE") unless defined?(@usage_path)
131
+ @usage_path
128
132
  end
129
133
 
130
134
  # Default file root to place extra files a command might need, placed
@@ -133,8 +137,8 @@ module Rails
133
137
  # For a Rails::Command::TestCommand placed in <tt>rails/command/test_command.rb</tt>
134
138
  # would return <tt>rails/test</tt>.
135
139
  def default_command_root
136
- path = File.expand_path(relative_command_path, __dir__)
137
- path if File.exist?(path)
140
+ @default_command_root = resolve_path(".") unless defined?(@default_command_root)
141
+ @default_command_root
138
142
  end
139
143
 
140
144
  private
@@ -145,37 +149,35 @@ module Rails
145
149
  else
146
150
  # Prevent exception about command without usage.
147
151
  # Some commands define their documentation differently.
148
- @usage ||= ""
152
+ @usage ||= meth
149
153
  @desc ||= ""
150
154
 
151
155
  super
152
156
  end
153
157
  end
154
158
 
155
- def command_root_namespace
156
- (namespace.split(":") - %w(rails)).join(":")
157
- end
158
-
159
- def relative_command_path
160
- File.join("../commands", *command_root_namespace.split(":"))
159
+ def namespaced_name(name)
160
+ *prefix, basename = namespace.delete_prefix("rails:").split(":")
161
+ prefix.concat([basename, name.to_s].uniq).join(":")
161
162
  end
162
163
 
163
- def namespaced_commands
164
- commands.keys.map do |key|
165
- if command_root_namespace.match?(/(\A|:)#{key}\z/)
166
- command_root_namespace
167
- else
168
- "#{command_root_namespace}:#{key}"
169
- end
170
- end
164
+ def resolve_path(path)
165
+ path = File.join("../commands", *namespace.delete_prefix("rails:").split(":"), path)
166
+ path = File.expand_path(path, __dir__)
167
+ path if File.exist?(path)
171
168
  end
172
169
  end
173
170
 
174
- def help
175
- if command_name = self.class.command_name
176
- self.class.command_help(shell, command_name)
177
- else
171
+ no_commands do
172
+ delegate :executable, to: :class
173
+ attr_reader :current_subcommand
174
+
175
+ def invoke_command(command, *) # :nodoc:
176
+ @current_subcommand ||= nil
177
+ original_subcommand, @current_subcommand = @current_subcommand, command.name
178
178
  super
179
+ ensure
180
+ @current_subcommand = original_subcommand
179
181
  end
180
182
  end
181
183
  end
@@ -9,31 +9,47 @@ module Rails
9
9
  extend ActiveSupport::Concern
10
10
 
11
11
  included do
12
- no_commands do
13
- class_attribute :environment_desc, default: "Specifies the environment to run this #{self.command_name} under (test/development/production)."
12
+ class_option :environment, aliases: "-e", type: :string,
13
+ desc: "The environment to run `#{self.command_name}` in (e.g. test / development / production)."
14
+ end
15
+
16
+ def initialize(...)
17
+ super
18
+
19
+ @environment_specified = options[:environment].present?
20
+
21
+ if !@environment_specified
22
+ self.options = options.merge(environment: Rails::Command.environment)
23
+ elsif !available_environments.include?(options[:environment])
24
+ self.options = options.merge(environment: expand_environment_name(options[:environment]))
14
25
  end
15
- class_option :environment, aliases: "-e", type: :string, desc: environment_desc
16
26
  end
17
27
 
18
28
  private
19
- def extract_environment_option_from_argument(default_environment: Rails::Command.environment)
20
- if options[:environment]
21
- self.options = options.merge(environment: acceptable_environment(options[:environment]))
22
- else
23
- self.options = options.merge(environment: default_environment)
24
- end
29
+ def require_application!
30
+ ENV["RAILS_ENV"] = environment
31
+ super
32
+ end
33
+
34
+ def environment
35
+ @environment ||= options[:environment]
36
+ end
37
+
38
+ def environment=(environment)
39
+ @environment = environment
25
40
  end
26
41
 
27
- def acceptable_environment(env = nil)
28
- if available_environments.include? env
29
- env
30
- else
31
- %w( production development test ).detect { |e| /^#{env}/.match?(e) } || env
32
- end
42
+ def environment_specified?
43
+ @environment_specified
33
44
  end
34
45
 
35
46
  def available_environments
36
- Dir["config/environments/*.rb"].map { |fname| File.basename(fname, ".*") }
47
+ @available_environments ||=
48
+ Dir["config/environments/*.rb"].map { |filename| File.basename(filename, ".*") }
49
+ end
50
+
51
+ def expand_environment_name(name)
52
+ %w[production development test].find { |full_name| full_name.start_with?(name) } || name
37
53
  end
38
54
  end
39
55
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "shellwords"
3
4
  require "active_support/encrypted_file"
4
5
 
5
6
  module Rails
@@ -7,27 +8,31 @@ module Rails
7
8
  module Helpers
8
9
  module Editor
9
10
  private
10
- def ensure_editor_available(command:)
11
- if ENV["EDITOR"].to_s.empty?
12
- say "No $EDITOR to open file in. Assign one like this:"
11
+ def editor
12
+ ENV["VISUAL"].to_s.empty? ? ENV["EDITOR"] : ENV["VISUAL"]
13
+ end
14
+
15
+ def display_hint_if_system_editor_not_specified
16
+ if editor.to_s.empty?
17
+ say "No $VISUAL or $EDITOR to open file in. Assign one like this:"
13
18
  say ""
14
- say %(EDITOR="mate --wait" #{command})
19
+ say %(VISUAL="mate --wait" #{executable(current_subcommand)})
15
20
  say ""
16
- say "For editors that fork and exit immediately, it's important to pass a wait flag,"
17
- say "otherwise the credentials will be saved immediately with no chance to edit."
21
+ say "For editors that fork and exit immediately, it's important to pass a wait flag;"
22
+ say "otherwise, the file will be saved immediately with no chance to edit."
18
23
 
19
- false
20
- else
21
24
  true
22
25
  end
23
26
  end
24
27
 
25
- def catch_editing_exceptions
26
- yield
28
+ def system_editor(file_path)
29
+ system(*Shellwords.split(editor), file_path.to_s)
30
+ end
31
+
32
+ def using_system_editor
33
+ display_hint_if_system_editor_not_specified || yield
27
34
  rescue Interrupt
28
35
  say "Aborted changing file: nothing saved."
29
- rescue ActiveSupport::EncryptedFile::MissingKeyError => error
30
- say error.message
31
36
  end
32
37
  end
33
38
  end