railties 7.0.10 → 7.1.0.beta1

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 (162) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +565 -234
  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 +1 -1
  9. data/lib/rails/application/bootstrap.rb +12 -3
  10. data/lib/rails/application/configuration.rb +179 -67
  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 +40 -33
  14. data/lib/rails/application.rb +116 -31
  15. data/lib/rails/backtrace_cleaner.rb +1 -1
  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 +19 -38
  52. data/lib/rails/commands/server/server_command.rb +32 -31
  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 +5 -0
  61. data/lib/rails/engine.rb +36 -16
  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 +14 -28
  65. data/lib/rails/generators/app_base.rb +353 -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 +19 -1
  69. data/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt +1 -1
  70. data/lib/rails/generators/generated_attribute.rb +2 -1
  71. data/lib/rails/generators/migration.rb +1 -2
  72. data/lib/rails/generators/model_helpers.rb +2 -1
  73. data/lib/rails/generators/rails/app/USAGE +15 -6
  74. data/lib/rails/generators/rails/app/app_generator.rb +84 -60
  75. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +107 -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 +4 -17
  80. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +3 -3
  81. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +0 -2
  82. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +3 -3
  83. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +59 -0
  84. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +10 -2
  85. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +28 -24
  86. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +11 -7
  87. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +2 -0
  88. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +2 -2
  89. data/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt +1 -1
  90. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_1.rb.tt +223 -0
  91. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +11 -9
  92. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +11 -13
  93. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +10 -19
  94. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +4 -0
  95. data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +6 -4
  96. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +10 -0
  97. data/lib/rails/generators/rails/app/templates/dockerignore.tt +43 -0
  98. data/lib/rails/generators/rails/app/templates/gitignore.tt +1 -9
  99. data/lib/rails/generators/rails/app/templates/node-version.tt +1 -0
  100. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +10 -8
  101. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +9 -7
  102. data/lib/rails/generators/rails/application_record/application_record_generator.rb +4 -0
  103. data/lib/rails/generators/rails/benchmark/benchmark_generator.rb +2 -1
  104. data/lib/rails/generators/rails/controller/USAGE +12 -4
  105. data/lib/rails/generators/rails/controller/controller_generator.rb +5 -0
  106. data/lib/rails/generators/rails/controller/templates/controller.rb.tt +1 -1
  107. data/lib/rails/generators/rails/credentials/credentials_generator.rb +29 -24
  108. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +8 -0
  109. data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +1 -2
  110. data/lib/rails/generators/rails/migration/USAGE +21 -11
  111. data/lib/rails/generators/rails/model/model_generator.rb +4 -0
  112. data/lib/rails/generators/rails/plugin/USAGE +17 -6
  113. data/lib/rails/generators/rails/plugin/plugin_generator.rb +5 -15
  114. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +2 -2
  115. data/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt +1 -1
  116. data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +1 -17
  117. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +0 -2
  118. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +4 -4
  119. data/lib/rails/generators/rails/resource/resource_generator.rb +6 -0
  120. data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +2 -1
  121. data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +1 -1
  122. data/lib/rails/generators/test_case.rb +2 -2
  123. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +1 -1
  124. data/lib/rails/generators/testing/{behaviour.rb → behavior.rb} +4 -1
  125. data/lib/rails/generators.rb +6 -14
  126. data/lib/rails/health_controller.rb +55 -0
  127. data/lib/rails/info.rb +1 -1
  128. data/lib/rails/info_controller.rb +31 -11
  129. data/lib/rails/mailers_controller.rb +15 -5
  130. data/lib/rails/rack/logger.rb +15 -12
  131. data/lib/rails/rackup/server.rb +15 -0
  132. data/lib/rails/railtie/configuration.rb +14 -1
  133. data/lib/rails/railtie.rb +18 -18
  134. data/lib/rails/ruby_version_check.rb +2 -0
  135. data/lib/rails/source_annotation_extractor.rb +67 -18
  136. data/lib/rails/tasks/engine.rake +8 -8
  137. data/lib/rails/tasks/framework.rake +4 -10
  138. data/lib/rails/tasks/log.rake +1 -1
  139. data/lib/rails/tasks/misc.rake +3 -14
  140. data/lib/rails/tasks/statistics.rake +5 -4
  141. data/lib/rails/tasks/tmp.rake +5 -5
  142. data/lib/rails/tasks/zeitwerk.rake +1 -1
  143. data/lib/rails/tasks.rb +0 -2
  144. data/lib/rails/templates/rails/mailers/email.html.erb +25 -0
  145. data/lib/rails/templates/rails/mailers/index.html.erb +14 -7
  146. data/lib/rails/templates/rails/mailers/mailer.html.erb +11 -5
  147. data/lib/rails/templates/rails/welcome/index.html.erb +1 -0
  148. data/lib/rails/test_help.rb +7 -7
  149. data/lib/rails/test_unit/line_filtering.rb +1 -1
  150. data/lib/rails/test_unit/reporter.rb +6 -2
  151. data/lib/rails/test_unit/runner.rb +36 -18
  152. data/lib/rails/test_unit/test_parser.rb +88 -0
  153. data/lib/rails/test_unit/testing.rake +13 -33
  154. data/lib/rails/version.rb +1 -1
  155. data/lib/rails.rb +15 -15
  156. metadata +69 -31
  157. data/RDOC_MAIN.rdoc +0 -97
  158. data/lib/rails/application/dummy_erb_compiler.rb +0 -18
  159. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt +0 -143
  160. data/lib/rails/generators/rails/model/USAGE +0 -113
  161. data/lib/rails/tasks/middleware.rake +0 -9
  162. 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,14 +220,22 @@ 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
- # Example:
236
+ # Convenience for loading config/foo.yml for the current \Rails env.
237
+ #
238
+ # Examples:
188
239
  #
189
240
  # # config/exception_notification.yml:
190
241
  # production:
@@ -195,15 +246,13 @@ module Rails
195
246
  # url: http://localhost:3001
196
247
  # namespace: my_app_development
197
248
  #
198
- # <code></code>
199
- #
200
249
  # # config/environments/production.rb
201
250
  # Rails.application.configure do
202
251
  # config.middleware.use ExceptionNotifier, config_for(:exception_notification)
203
252
  # end
204
253
  #
205
- # You can also store configurations in a shared section which will be merged
206
- # with the environment configuration
254
+ # # You can also store configurations in a shared section which will be
255
+ # # merged with the environment configuration
207
256
  #
208
257
  # # config/example.yml
209
258
  # shared:
@@ -216,8 +265,6 @@ module Rails
216
265
  # bar:
217
266
  # qux: 2
218
267
  #
219
- # <code></code>
220
- #
221
268
  # # development environment
222
269
  # Rails.application.config_for(:example)[:foo][:bar]
223
270
  # # => { baz: 1, qux: 2 }
@@ -248,16 +295,17 @@ module Rails
248
295
  end
249
296
  end
250
297
 
251
- # Stores some of the Rails initial environment parameters which
298
+ # Stores some of the \Rails initial environment parameters which
252
299
  # will be used by middlewares and engines to configure themselves.
253
300
  def env_config
254
301
  @app_env_config ||= super.merge(
255
- "action_dispatch.parameter_filter" => config.filter_parameters,
302
+ "action_dispatch.parameter_filter" => filter_parameters,
256
303
  "action_dispatch.redirect_filter" => config.filter_redirect,
257
304
  "action_dispatch.secret_key_base" => secret_key_base,
258
305
  "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions,
259
306
  "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local,
260
307
  "action_dispatch.log_rescued_responses" => config.action_dispatch.log_rescued_responses,
308
+ "action_dispatch.debug_exception_log_level" => ActiveSupport::Logger.const_get(config.action_dispatch.debug_exception_log_level.to_s.upcase),
261
309
  "action_dispatch.logger" => Rails.logger,
262
310
  "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner,
263
311
  "action_dispatch.key_generator" => key_generator,
@@ -340,7 +388,7 @@ module Rails
340
388
  # Rails application, you will need to add lib to $LOAD_PATH on your own in case
341
389
  # you need to load files in lib/ during the application configuration as well.
342
390
  def self.add_lib_to_load_path!(root) # :nodoc:
343
- path = File.join root, "lib"
391
+ path = File.join(root, "lib")
344
392
  if File.exist?(path) && !$LOAD_PATH.include?(path)
345
393
  $LOAD_PATH.unshift(path)
346
394
  end
@@ -390,6 +438,9 @@ module Rails
390
438
  attr_writer :config
391
439
 
392
440
  def secrets
441
+ Rails.deprecator.warn(<<~MSG.squish)
442
+ `Rails.application.secrets` is deprecated in favor of `Rails.application.credentials` and will be removed in Rails 7.2.
443
+ MSG
393
444
  @secrets ||= begin
394
445
  secrets = ActiveSupport::OrderedOptions.new
395
446
  files = config.paths["config/secrets"].existent
@@ -410,14 +461,20 @@ module Rails
410
461
  # including the ones that sign and encrypt cookies.
411
462
  #
412
463
  # In development and test, this is randomly generated and stored in a
413
- # temporary file in <tt>tmp/development_secret.txt</tt>.
464
+ # temporary file in <tt>tmp/local_secret.txt</tt>.
465
+ #
466
+ # You can also set <tt>ENV["SECRET_KEY_BASE_DUMMY"]</tt> to trigger the use of a randomly generated
467
+ # secret_key_base that's stored in a temporary file. This is useful when precompiling assets for
468
+ # production as part of a build step that otherwise does not need access to the production secrets.
469
+ #
470
+ # Dockerfile example: <tt>RUN SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile</tt>.
414
471
  #
415
472
  # In all other environments, we look for it first in <tt>ENV["SECRET_KEY_BASE"]</tt>,
416
473
  # then +credentials.secret_key_base+, and finally +secrets.secret_key_base+. For most applications,
417
474
  # the correct place to store it is in the encrypted credentials file.
418
475
  def secret_key_base
419
- if Rails.env.development? || Rails.env.test?
420
- secrets.secret_key_base ||= generate_development_secret
476
+ if Rails.env.local? || ENV["SECRET_KEY_BASE_DUMMY"]
477
+ config.secret_key_base ||= generate_local_secret
421
478
  else
422
479
  validate_secret_key_base(
423
480
  ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
@@ -491,6 +548,11 @@ module Rails
491
548
  ordered_railties.flatten - [self]
492
549
  end
493
550
 
551
+ def load_generators(app = self) # :nodoc:
552
+ app.ensure_generator_templates_added
553
+ super
554
+ end
555
+
494
556
  # Eager loads the application code.
495
557
  def eager_load!
496
558
  Rails.autoloaders.each(&:eager_load)
@@ -580,21 +642,35 @@ module Rails
580
642
  end
581
643
  end
582
644
 
583
- private
584
- def generate_development_secret
585
- if secrets.secret_key_base.nil?
586
- key_file = Rails.root.join("tmp/development_secret.txt")
645
+ def ensure_generator_templates_added
646
+ configured_paths = config.generators.templates
647
+ configured_paths.unshift(*(paths["lib/templates"].existent - configured_paths))
648
+ end
587
649
 
588
- if !File.exist?(key_file)
650
+ private
651
+ def generate_local_secret
652
+ if config.secret_key_base.nil?
653
+ key_file = Rails.root.join("tmp/local_secret.txt")
654
+
655
+ if File.exist?(key_file)
656
+ config.secret_key_base = File.binread(key_file)
657
+ elsif secrets_secret_key_base
658
+ config.secret_key_base = secrets_secret_key_base
659
+ else
589
660
  random_key = SecureRandom.hex(64)
590
661
  FileUtils.mkdir_p(key_file.dirname)
591
662
  File.binwrite(key_file, random_key)
663
+ config.secret_key_base = File.binread(key_file)
592
664
  end
593
-
594
- secrets.secret_key_base = File.binread(key_file)
595
665
  end
596
666
 
597
- secrets.secret_key_base
667
+ config.secret_key_base
668
+ end
669
+
670
+ def secrets_secret_key_base
671
+ Rails.deprecator.silence do
672
+ secrets.secret_key_base
673
+ end
598
674
  end
599
675
 
600
676
  def build_request(env)
@@ -611,5 +687,14 @@ module Rails
611
687
  def coerce_same_site_protection(protection)
612
688
  protection.respond_to?(:call) ? protection : proc { protection }
613
689
  end
690
+
691
+ def filter_parameters
692
+ if config.precompile_filter_parameters
693
+ config.filter_parameters.replace(
694
+ ActiveSupport::ParameterFilter.precompile_filters(config.filter_parameters)
695
+ )
696
+ end
697
+ config.filter_parameters
698
+ end
614
699
  end
615
700
  end
@@ -4,7 +4,7 @@ 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
 
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