railties 7.0.8 → 7.2.0

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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +188 -268
  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 +67 -1
  7. data/lib/rails/all.rb +1 -3
  8. data/lib/rails/api/task.rb +39 -6
  9. data/lib/rails/application/bootstrap.rb +28 -10
  10. data/lib/rails/application/configuration.rb +228 -72
  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 +50 -33
  14. data/lib/rails/application.rb +110 -76
  15. data/lib/rails/backtrace_cleaner.rb +19 -4
  16. data/lib/rails/cli.rb +5 -3
  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/app/update_command.rb +93 -0
  24. data/lib/rails/commands/application/application_command.rb +2 -0
  25. data/lib/rails/commands/boot/boot_command.rb +14 -0
  26. data/lib/rails/commands/console/console_command.rb +11 -30
  27. data/lib/rails/commands/console/irb_console.rb +137 -0
  28. data/lib/rails/commands/credentials/USAGE +53 -55
  29. data/lib/rails/commands/credentials/credentials_command/diffing.rb +5 -3
  30. data/lib/rails/commands/credentials/credentials_command.rb +64 -70
  31. data/lib/rails/commands/db/system/change/change_command.rb +2 -1
  32. data/lib/rails/commands/dbconsole/dbconsole_command.rb +32 -131
  33. data/lib/rails/commands/destroy/destroy_command.rb +3 -2
  34. data/lib/rails/commands/dev/dev_command.rb +1 -6
  35. data/lib/rails/commands/devcontainer/devcontainer_command.rb +39 -0
  36. data/lib/rails/commands/encrypted/USAGE +15 -20
  37. data/lib/rails/commands/encrypted/encrypted_command.rb +46 -35
  38. data/lib/rails/commands/gem_help/USAGE +16 -0
  39. data/lib/rails/commands/gem_help/gem_help_command.rb +13 -0
  40. data/lib/rails/commands/generate/generate_command.rb +2 -2
  41. data/lib/rails/commands/help/USAGE +13 -13
  42. data/lib/rails/commands/help/help_command.rb +21 -2
  43. data/lib/rails/commands/initializers/initializers_command.rb +1 -4
  44. data/lib/rails/commands/middleware/middleware_command.rb +17 -0
  45. data/lib/rails/commands/new/new_command.rb +2 -0
  46. data/lib/rails/commands/notes/notes_command.rb +2 -1
  47. data/lib/rails/commands/plugin/plugin_command.rb +2 -0
  48. data/lib/rails/commands/rake/rake_command.rb +25 -22
  49. data/lib/rails/commands/restart/restart_command.rb +14 -0
  50. data/lib/rails/commands/routes/routes_command.rb +13 -1
  51. data/lib/rails/commands/runner/USAGE +14 -12
  52. data/lib/rails/commands/runner/runner_command.rb +42 -19
  53. data/lib/rails/commands/secret/secret_command.rb +13 -0
  54. data/lib/rails/commands/server/server_command.rb +37 -34
  55. data/lib/rails/commands/test/USAGE +14 -0
  56. data/lib/rails/commands/test/test_command.rb +58 -14
  57. data/lib/rails/commands/unused_routes/unused_routes_command.rb +75 -0
  58. data/lib/rails/commands/version/version_command.rb +1 -0
  59. data/lib/rails/configuration.rb +15 -6
  60. data/lib/rails/console/app.rb +5 -35
  61. data/lib/rails/console/helpers.rb +5 -16
  62. data/lib/rails/console/methods.rb +23 -0
  63. data/lib/rails/deprecator.rb +7 -0
  64. data/lib/rails/engine/configuration.rb +50 -6
  65. data/lib/rails/engine.rb +51 -23
  66. data/lib/rails/gem_version.rb +3 -3
  67. data/lib/rails/generators/actions.rb +6 -15
  68. data/lib/rails/generators/active_model.rb +28 -14
  69. data/lib/rails/generators/app_base.rb +382 -88
  70. data/lib/rails/generators/app_name.rb +3 -14
  71. data/lib/rails/generators/base.rb +21 -9
  72. data/lib/rails/generators/database.rb +231 -35
  73. data/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt +1 -1
  74. data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +2 -0
  75. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +2 -0
  76. data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +2 -0
  77. data/lib/rails/generators/generated_attribute.rb +38 -1
  78. data/lib/rails/generators/migration.rb +4 -5
  79. data/lib/rails/generators/model_helpers.rb +2 -1
  80. data/lib/rails/generators/rails/app/USAGE +22 -6
  81. data/lib/rails/generators/rails/app/app_generator.rb +132 -82
  82. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +110 -0
  83. data/lib/rails/generators/rails/app/templates/Gemfile.tt +19 -21
  84. data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +4 -0
  85. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +8 -1
  86. data/lib/rails/generators/rails/app/templates/app/views/layouts/mailer.html.erb.tt +1 -1
  87. data/lib/rails/generators/rails/app/templates/app/views/pwa/manifest.json.erb.tt +22 -0
  88. data/lib/rails/generators/rails/app/templates/app/views/pwa/service-worker.js +26 -0
  89. data/lib/rails/generators/rails/app/templates/bin/brakeman.tt +6 -0
  90. data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +7 -0
  91. data/lib/rails/generators/rails/app/templates/bin/setup.tt +15 -2
  92. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +6 -17
  93. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +3 -3
  94. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +11 -6
  95. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +10 -3
  96. data/lib/rails/generators/rails/app/templates/config/databases/{jdbcmysql.yml.tt → trilogy.yml.tt} +12 -7
  97. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +25 -8
  98. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +37 -28
  99. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +20 -13
  100. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +2 -0
  101. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +2 -2
  102. data/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt +1 -1
  103. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +4 -4
  104. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +70 -0
  105. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +11 -9
  106. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +11 -13
  107. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +24 -34
  108. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +9 -1
  109. data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +6 -4
  110. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +15 -0
  111. data/lib/rails/generators/rails/app/templates/dockerignore.tt +56 -0
  112. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +138 -0
  113. data/lib/rails/generators/rails/app/templates/github/dependabot.yml +12 -0
  114. data/lib/rails/generators/rails/app/templates/gitignore.tt +7 -11
  115. data/lib/rails/generators/rails/app/templates/node-version.tt +1 -0
  116. data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +66 -0
  117. data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
  118. data/lib/rails/generators/rails/app/templates/public/icon.svg +3 -0
  119. data/lib/rails/generators/rails/app/templates/rubocop.yml.tt +8 -0
  120. data/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt +1 -1
  121. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +10 -8
  122. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +9 -7
  123. data/lib/rails/generators/rails/application_record/application_record_generator.rb +4 -0
  124. data/lib/rails/generators/rails/benchmark/benchmark_generator.rb +2 -1
  125. data/lib/rails/generators/rails/controller/USAGE +12 -4
  126. data/lib/rails/generators/rails/controller/controller_generator.rb +6 -1
  127. data/lib/rails/generators/rails/controller/templates/controller.rb.tt +1 -1
  128. data/lib/rails/generators/rails/credentials/credentials_generator.rb +29 -24
  129. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +8 -0
  130. data/lib/rails/generators/rails/db/system/change/change_generator.rb +146 -5
  131. data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +166 -0
  132. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +3 -0
  133. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/compose.yaml.tt +47 -0
  134. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +37 -0
  135. data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +1 -2
  136. data/lib/rails/generators/rails/migration/USAGE +21 -11
  137. data/lib/rails/generators/rails/migration/migration_generator.rb +4 -0
  138. data/lib/rails/generators/rails/model/model_generator.rb +4 -0
  139. data/lib/rails/generators/rails/plugin/USAGE +17 -6
  140. data/lib/rails/generators/rails/plugin/plugin_generator.rb +43 -22
  141. data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +2 -2
  142. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +7 -3
  143. data/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt +1 -1
  144. data/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +2 -0
  145. data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +1 -17
  146. data/lib/rails/generators/rails/plugin/templates/bin/rubocop.tt +7 -0
  147. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +103 -0
  148. data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +12 -0
  149. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +0 -2
  150. data/lib/rails/generators/rails/plugin/templates/rubocop.yml.tt +8 -0
  151. data/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt +1 -1
  152. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +4 -4
  153. data/lib/rails/generators/rails/resource/resource_generator.rb +6 -0
  154. data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +2 -1
  155. data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +1 -1
  156. data/lib/rails/generators/test_case.rb +2 -2
  157. data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb.tt +6 -4
  158. data/lib/rails/generators/test_unit/mailer/templates/preview.rb.tt +3 -2
  159. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +16 -2
  160. data/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt +2 -2
  161. data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +2 -2
  162. data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +2 -0
  163. data/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt +1 -1
  164. data/lib/rails/generators/testing/assertions.rb +20 -0
  165. data/lib/rails/generators/testing/{behaviour.rb → behavior.rb} +8 -4
  166. data/lib/rails/generators.rb +7 -15
  167. data/lib/rails/health_controller.rb +55 -0
  168. data/lib/rails/info.rb +3 -3
  169. data/lib/rails/info_controller.rb +31 -11
  170. data/lib/rails/mailers_controller.rb +29 -6
  171. data/lib/rails/paths.rb +15 -12
  172. data/lib/rails/pwa_controller.rb +15 -0
  173. data/lib/rails/rack/logger.rb +27 -16
  174. data/lib/rails/rackup/server.rb +15 -0
  175. data/lib/rails/railtie/configurable.rb +2 -2
  176. data/lib/rails/railtie/configuration.rb +14 -1
  177. data/lib/rails/railtie.rb +20 -21
  178. data/lib/rails/source_annotation_extractor.rb +67 -18
  179. data/lib/rails/tasks/engine.rake +8 -8
  180. data/lib/rails/tasks/framework.rake +2 -34
  181. data/lib/rails/tasks/log.rake +1 -1
  182. data/lib/rails/tasks/misc.rake +3 -14
  183. data/lib/rails/tasks/statistics.rake +5 -4
  184. data/lib/rails/tasks/tmp.rake +6 -6
  185. data/lib/rails/tasks/zeitwerk.rake +15 -35
  186. data/lib/rails/tasks.rb +0 -2
  187. data/lib/rails/templates/layouts/application.html.erb +1 -1
  188. data/lib/rails/templates/rails/mailers/email.html.erb +44 -8
  189. data/lib/rails/templates/rails/mailers/index.html.erb +14 -7
  190. data/lib/rails/templates/rails/mailers/mailer.html.erb +11 -5
  191. data/lib/rails/templates/rails/welcome/index.html.erb +5 -2
  192. data/lib/rails/test_help.rb +11 -18
  193. data/lib/rails/test_unit/line_filtering.rb +1 -1
  194. data/lib/rails/test_unit/reporter.rb +14 -4
  195. data/lib/rails/test_unit/runner.rb +62 -20
  196. data/lib/rails/test_unit/test_parser.rb +133 -0
  197. data/lib/rails/test_unit/testing.rake +13 -33
  198. data/lib/rails/testing/maintain_test_schema.rb +16 -0
  199. data/lib/rails/version.rb +1 -1
  200. data/lib/rails/zeitwerk_checker.rb +15 -0
  201. data/lib/rails.rb +20 -17
  202. metadata +89 -42
  203. data/RDOC_MAIN.rdoc +0 -97
  204. data/lib/rails/app_updater.rb +0 -40
  205. data/lib/rails/application/dummy_erb_compiler.rb +0 -18
  206. data/lib/rails/commands/secrets/USAGE +0 -66
  207. data/lib/rails/commands/secrets/secrets_command.rb +0 -65
  208. data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +0 -68
  209. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +0 -70
  210. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +0 -24
  211. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +0 -62
  212. data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +0 -53
  213. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt +0 -143
  214. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon-precomposed.png +0 -0
  215. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon.png +0 -0
  216. data/lib/rails/generators/rails/app/templates/public/favicon.ico +0 -0
  217. data/lib/rails/generators/rails/model/USAGE +0 -113
  218. data/lib/rails/ruby_version_check.rb +0 -15
  219. data/lib/rails/secrets.rb +0 -110
  220. data/lib/rails/tasks/middleware.rake +0 -9
  221. data/lib/rails/tasks/restart.rake +0 -9
@@ -9,42 +9,45 @@ module Rails
9
9
 
10
10
  class << self
11
11
  def printing_commands
12
- formatted_rake_tasks.map(&:first)
12
+ rake_tasks.filter_map do |task|
13
+ if task.comment && task.locations.any?(non_app_file_pattern)
14
+ [task.name_with_args, task.comment]
15
+ end
16
+ end
13
17
  end
14
18
 
15
19
  def perform(task, args, config)
16
- require_rake
17
-
18
- Rake.with_application do |rake|
19
- rake.init("rails", [task, *args])
20
- rake.load_rakefile
21
- if Rails.respond_to?(:root)
22
- rake.options.suppress_backtrace_pattern = /\A(?!#{Regexp.quote(Rails.root.to_s)})/
20
+ with_rake(task, *args) do |rake|
21
+ if unrecognized_task = (rake.top_level_tasks - ["default"]).find { |task| !rake.lookup(task[/[^\[]+/]) }
22
+ @rake_tasks = rake.tasks
23
+ raise UnrecognizedCommandError.new(unrecognized_task)
23
24
  end
25
+
26
+ rake.options.suppress_backtrace_pattern = non_app_file_pattern
24
27
  rake.standard_exception_handling { rake.top_level }
25
28
  end
26
29
  end
27
30
 
28
31
  private
29
- def rake_tasks
30
- require_rake
31
-
32
- return @rake_tasks if defined?(@rake_tasks)
33
-
34
- require_application!
32
+ def non_app_file_pattern
33
+ /\A(?!#{Regexp.quote Rails::Command.root.to_s})/
34
+ end
35
35
 
36
+ def with_rake(*args, &block)
37
+ require "rake"
36
38
  Rake::TaskManager.record_task_metadata = true
37
- Rake.application.instance_variable_set(:@name, "rails")
38
- load_tasks
39
- @rake_tasks = Rake.application.tasks.select(&:comment)
40
- end
41
39
 
42
- def formatted_rake_tasks
43
- rake_tasks.map { |t| [ t.name_with_args, t.comment ] }
40
+ result = nil
41
+ Rake.with_application do |rake|
42
+ rake.init(bin, args) unless args.empty?
43
+ rake.load_rakefile
44
+ result = block.call(rake)
45
+ end
46
+ result
44
47
  end
45
48
 
46
- def require_rake
47
- require "rake" # Defer booting Rake until we know it's needed.
49
+ def rake_tasks
50
+ @rake_tasks ||= with_rake(&:tasks)
48
51
  end
49
52
  end
50
53
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module Command
5
+ class RestartCommand < Base # :nodoc:
6
+ desc "restart", "Restart app by touching tmp/restart.txt"
7
+ def perform
8
+ require "fileutils"
9
+ FileUtils.mkdir_p Rails::Command.application_root.join("tmp")
10
+ FileUtils.touch Rails::Command.application_root.join("tmp/restart.txt")
11
+ end
12
+ end
13
+ end
14
+ end
@@ -8,9 +8,21 @@ module Rails
8
8
  class_option :controller, aliases: "-c", desc: "Filter by a specific controller, e.g. PostsController or Admin::PostsController."
9
9
  class_option :grep, aliases: "-g", desc: "Grep routes by a specific pattern."
10
10
  class_option :expanded, type: :boolean, aliases: "-E", desc: "Print routes expanded vertically with parts explained."
11
+ class_option :unused, type: :boolean, aliases: "-u", desc: "Print unused routes."
11
12
 
13
+ no_commands do
14
+ def invoke_command(*)
15
+ if options.key?("unused")
16
+ Rails::Command.invoke "unused_routes", ARGV
17
+ else
18
+ super
19
+ end
20
+ end
21
+ end
22
+
23
+ desc "routes", "List all the defined routes"
12
24
  def perform(*)
13
- require_application_and_environment!
25
+ boot_application!
14
26
  require "action_dispatch/routing/inspector"
15
27
 
16
28
  say inspector.format(formatter, routes_filter)
@@ -1,20 +1,22 @@
1
- Examples:
1
+ Description:
2
+ The Rails `runner` allows running Ruby code in the context of your application.
2
3
 
3
- Run `puts Rails.env` after loading the app:
4
+ Examples:
5
+ Run `puts Rails.env` after loading the app:
4
6
 
5
- <%= executable %> 'puts Rails.env'
7
+ <%= executable %> 'puts Rails.env'
6
8
 
7
- Run the Ruby file located at `path/to/filename.rb` after loading the app:
9
+ Run the Ruby file located at `path/to/filename.rb` after loading the app:
8
10
 
9
- <%= executable %> path/to/filename.rb
11
+ <%= executable %> path/to/filename.rb
10
12
 
11
- Run the Ruby script read from stdin after loading the app:
12
- <%= executable %> -
13
+ Run the Ruby script read from stdin after loading the app:
13
14
 
14
- <% unless Gem.win_platform? %>
15
- You can also use the runner command as a shebang line for your executables:
15
+ <%= executable %> -
16
+ <% unless Gem.win_platform? -%>
16
17
 
17
- #!/usr/bin/env <%= File.expand_path(executable) %>
18
+ You can also use the runner command as a shebang line for your executables:
18
19
 
19
- Product.all.each { |p| p.price *= 2 ; p.save! }
20
- <% end %>
20
+ #!/usr/bin/env <%= File.expand_path(executable) %>
21
+ Product.all.each { |p| p.price *= 2 ; p.save! }
22
+ <% end -%>
@@ -7,52 +7,75 @@ module Rails
7
7
  class RunnerCommand < Base # :nodoc:
8
8
  include EnvironmentArgument
9
9
 
10
- self.environment_desc = "The environment for the runner to operate under (test/development/production)"
10
+ class_option :skip_executor, type: :boolean, aliases: "-w", desc: "Don't wrap with Rails Executor", default: false
11
11
 
12
12
  no_commands do
13
- def help
13
+ def help(command_name = nil, *)
14
14
  super
15
- say self.class.desc
15
+ if command_name == "runner"
16
+ say ""
17
+ say self.class.class_usage
18
+ end
16
19
  end
17
20
  end
18
21
 
19
- def self.banner(*)
20
- "#{super} [<'Some.ruby(code)'> | <filename.rb> | -]"
21
- end
22
-
22
+ desc "runner [<'Some.ruby(code)'> | <filename.rb> | -]",
23
+ "Run Ruby code in the context of your application"
23
24
  def perform(code_or_file = nil, *command_argv)
24
- extract_environment_option_from_argument
25
-
26
25
  unless code_or_file
27
26
  help
28
27
  exit 1
29
28
  end
30
29
 
31
- ENV["RAILS_ENV"] = options[:environment]
32
-
33
- require_application_and_environment!
30
+ boot_application!
34
31
  Rails.application.load_runner
35
32
 
36
33
  ARGV.replace(command_argv)
37
34
 
35
+ wrap_with_executor = !options[:skip_executor]
38
36
  if code_or_file == "-"
39
- eval($stdin.read, TOPLEVEL_BINDING, "stdin")
37
+ conditional_executor(wrap_with_executor, source: "application.runner.railties") do
38
+ eval($stdin.read, TOPLEVEL_BINDING, "stdin")
39
+ end
40
40
  elsif File.exist?(code_or_file)
41
41
  expanded_file_path = File.expand_path code_or_file
42
42
  $0 = expanded_file_path
43
- Kernel.load expanded_file_path
43
+ conditional_executor(wrap_with_executor, source: "application.runner.railties") do
44
+ Kernel.load expanded_file_path
45
+ end
44
46
  else
45
47
  begin
46
- eval(code_or_file, TOPLEVEL_BINDING, __FILE__, __LINE__)
48
+ conditional_executor(wrap_with_executor, source: "application.runner.railties") do
49
+ eval(code_or_file, TOPLEVEL_BINDING, __FILE__, __LINE__)
50
+ end
47
51
  rescue SyntaxError, NameError => e
48
- error "Please specify a valid ruby command or the path of a script to run."
49
- error "Run '#{self.class.executable} -h' for help."
50
- error ""
51
- error e
52
+ if looks_like_a_file_path?(code_or_file)
53
+ error "The file #{code_or_file} could not be found, please check and try again."
54
+ error "Run '#{self.class.executable} -h' for help."
55
+ else
56
+ error "Please specify a valid ruby command or the path of a script to run."
57
+ error "Run '#{self.class.executable} -h' for help."
58
+ error ""
59
+ error e
60
+ end
61
+
52
62
  exit 1
53
63
  end
54
64
  end
55
65
  end
66
+
67
+ private
68
+ def conditional_executor(enabled, **args, &block)
69
+ if enabled
70
+ Rails.application.executor.wrap(**args, &block)
71
+ else
72
+ yield
73
+ end
74
+ end
75
+
76
+ def looks_like_a_file_path?(code_or_file)
77
+ code_or_file.ends_with?(".rb")
78
+ end
56
79
  end
57
80
  end
58
81
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module Command
5
+ class SecretCommand < Base # :nodoc:
6
+ desc "secret", "Generate a cryptographically secure secret key (this is typically used to generate a secret for cookie sessions)."
7
+ def perform
8
+ require "securerandom"
9
+ puts SecureRandom.hex(64)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -3,12 +3,12 @@
3
3
  require "fileutils"
4
4
  require "action_dispatch"
5
5
  require "rails"
6
- require "active_support/core_ext/string/filters"
7
6
  require "rails/dev_caching"
8
7
  require "rails/command/environment_argument"
8
+ require "rails/rackup/server"
9
9
 
10
10
  module Rails
11
- class Server < ::Rack::Server
11
+ class Server < Rackup::Server
12
12
  class Options
13
13
  def parse!(args)
14
14
  Rails::Command::ServerCommand.new([], args).server_options
@@ -79,13 +79,13 @@ module Rails
79
79
  console.formatter = Rails.logger.formatter
80
80
  console.level = Rails.logger.level
81
81
 
82
- unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT)
83
- Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
82
+ unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDERR, STDOUT)
83
+ Rails.logger.broadcast_to(console)
84
84
  end
85
85
  end
86
86
 
87
87
  def use_puma?
88
- server.to_s == "Rack::Handler::Puma"
88
+ server.to_s.end_with?("Handler::Puma")
89
89
  end
90
90
  end
91
91
 
@@ -93,30 +93,32 @@ module Rails
93
93
  class ServerCommand < Base # :nodoc:
94
94
  include EnvironmentArgument
95
95
 
96
+ RACK_HANDLER_GEMS = %w(cgi webrick scgi thin puma unicorn falcon)
96
97
  # Hard-coding a bunch of handlers here as we don't have a public way of
97
- # querying them from the Rack::Handler registry.
98
- RACK_SERVERS = %w(cgi fastcgi webrick lsws scgi thin puma unicorn falcon)
98
+ # querying them from the Rackup::Handler registry.
99
+ RACK_HANDLERS = RACK_HANDLER_GEMS + %w(fastcgi lsws)
100
+ RECOMMENDED_SERVER = "puma"
99
101
 
100
102
  DEFAULT_PORT = 3000
101
103
  DEFAULT_PIDFILE = "tmp/pids/server.pid"
102
104
 
103
105
  class_option :port, aliases: "-p", type: :numeric,
104
- desc: "Runs Rails on the specified port - defaults to 3000.", banner: :port
106
+ desc: "Run Rails on the specified port - defaults to 3000.", banner: :port
105
107
  class_option :binding, aliases: "-b", type: :string,
106
- desc: "Binds Rails to the specified IP - defaults to 'localhost' in development and '0.0.0.0' in other environments'.",
108
+ desc: "Bind Rails to the specified IP - defaults to 'localhost' in development and '0.0.0.0' in other environments'.",
107
109
  banner: :IP
108
110
  class_option :config, aliases: "-c", type: :string, default: "config.ru",
109
- desc: "Uses a custom rackup configuration.", banner: :file
111
+ desc: "Use a custom rackup configuration.", banner: :file
110
112
  class_option :daemon, aliases: "-d", type: :boolean, default: false,
111
- desc: "Runs server as a Daemon."
113
+ desc: "Run server as a Daemon."
112
114
  class_option :using, aliases: "-u", type: :string,
113
- desc: "Specifies the Rack server used to run the application (thin/puma/webrick).", banner: :name
115
+ desc: "Specify the Rack server used to run the application (thin/puma/webrick).", banner: :name
114
116
  class_option :pid, aliases: "-P", type: :string,
115
- desc: "Specifies the PID file - defaults to #{DEFAULT_PIDFILE}."
117
+ desc: "Specify the PID file. Defaults to #{DEFAULT_PIDFILE} in development."
116
118
  class_option :dev_caching, aliases: "-C", type: :boolean, default: nil,
117
- desc: "Specifies whether to perform caching in development."
119
+ desc: "Specify whether to perform caching in development."
118
120
  class_option :restart, type: :boolean, default: nil, hide: true
119
- class_option :early_hints, type: :boolean, default: nil, desc: "Enables HTTP/2 early hints."
121
+ class_option :early_hints, type: :boolean, default: nil, desc: "Enable HTTP/2 early hints."
120
122
  class_option :log_to_stdout, type: :boolean, default: nil, optional: true,
121
123
  desc: "Whether to log to stdout. Enabled by default in development when not daemonized."
122
124
 
@@ -126,8 +128,8 @@ module Rails
126
128
  @original_options = local_options - %w( --restart )
127
129
  end
128
130
 
131
+ desc "server", "Start the Rails server"
129
132
  def perform
130
- extract_environment_option_from_argument
131
133
  set_application_directory!
132
134
  prepare_restart
133
135
 
@@ -227,7 +229,7 @@ module Rails
227
229
  end
228
230
 
229
231
  def restart_command
230
- "bin/rails server #{@original_options.join(" ")} --restart"
232
+ "#{executable} #{@original_options.join(" ")} --restart"
231
233
  end
232
234
 
233
235
  def early_hints
@@ -241,36 +243,37 @@ module Rails
241
243
  end
242
244
 
243
245
  def pid
244
- File.expand_path(options[:pid] || ENV.fetch("PIDFILE", DEFAULT_PIDFILE))
245
- end
246
-
247
- def self.banner(*)
248
- "rails server -u [thin/puma/webrick] [options]"
246
+ default_pidfile = environment == "development" ? DEFAULT_PIDFILE : nil
247
+ pid = options[:pid] || ENV["PIDFILE"] || default_pidfile
248
+ File.expand_path(pid) if pid
249
249
  end
250
250
 
251
251
  def prepare_restart
252
- FileUtils.rm_f(pid) if options[:restart]
252
+ FileUtils.rm_f(pid) if pid && options[:restart]
253
253
  end
254
254
 
255
255
  def rack_server_suggestion(server)
256
- if server.in?(RACK_SERVERS)
256
+ if server.nil?
257
+ <<~MSG
258
+ Could not find a server gem. Maybe you need to add one to the Gemfile?
259
+
260
+ gem "#{RECOMMENDED_SERVER}"
261
+
262
+ Run `#{executable} --help` for more options.
263
+ MSG
264
+ elsif server.in?(RACK_HANDLER_GEMS)
257
265
  <<~MSG
258
266
  Could not load server "#{server}". Maybe you need to the add it to the Gemfile?
259
267
 
260
268
  gem "#{server}"
261
269
 
262
- Run `bin/rails server --help` for more options.
270
+ Run `#{executable} --help` for more options.
263
271
  MSG
264
272
  else
265
- error = CorrectableError.new("Could not find server '#{server}'.", server, RACK_SERVERS)
266
- if error.respond_to?(:detailed_message)
267
- formatted_message = error.detailed_message
268
- else
269
- formatted_message = error.message
270
- end
273
+ error = CorrectableNameError.new("Could not find server '#{server}'.", server, RACK_HANDLERS)
271
274
  <<~MSG
272
- #{formatted_message}
273
- Run `bin/rails server --help` for more options.
275
+ #{error.detailed_message}
276
+ Run `#{executable} --help` for more options.
274
277
  MSG
275
278
  end
276
279
  end
@@ -279,7 +282,7 @@ module Rails
279
282
  say <<~MSG
280
283
  => Booting #{ActiveSupport::Inflector.demodulize(server)}
281
284
  => Rails #{Rails.version} application starting in #{Rails.env} #{url}
282
- => Run `bin/rails server --help` for more startup options
285
+ => Run `#{executable} --help` for more startup options
283
286
  MSG
284
287
  end
285
288
  end
@@ -0,0 +1,14 @@
1
+ Examples:
2
+ You can run a single test by appending a line number to a filename:
3
+
4
+ <%= executable %> test/models/user_test.rb:27
5
+
6
+ You can run multiple tests with in a line range by appending the line range to a filename:
7
+
8
+ <%= executable %> test/models/user_test.rb:10-20
9
+
10
+ You can run multiple files and directories at the same time:
11
+
12
+ <%= executable %> test/controllers test/integration/login_test.rb
13
+
14
+ By default test failures and errors are reported inline during a run.
@@ -1,37 +1,81 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rails/command"
4
+ require "rails/commands/rake/rake_command"
4
5
  require "rails/test_unit/runner"
5
6
  require "rails/test_unit/reporter"
6
7
 
7
8
  module Rails
8
9
  module Command
9
10
  class TestCommand < Base # :nodoc:
11
+ def self.executable(*args)
12
+ args.empty? ? Rails::TestUnitReporter.executable : super
13
+ end
14
+
10
15
  no_commands do
11
- def help
12
- say "Usage: #{Rails::TestUnitReporter.executable} [options] [files or directories]"
13
- say ""
14
- say "You can run a single test by appending a line number to a filename:"
15
- say ""
16
- say " #{Rails::TestUnitReporter.executable} test/models/user_test.rb:27"
17
- say ""
18
- say "You can run multiple files and directories at the same time:"
19
- say ""
20
- say " #{Rails::TestUnitReporter.executable} test/controllers test/integration/login_test.rb"
16
+ def help(command_name = nil, *)
17
+ super
18
+ if command_name == "test"
19
+ say ""
20
+ say self.class.class_usage
21
+ end
21
22
  say ""
22
- say "By default test failures and errors are reported inline during a run."
23
- say ""
24
-
25
23
  Minitest.run(%w(--help))
26
24
  end
27
25
  end
28
26
 
29
- def perform(*)
27
+ desc "test [PATHS...]", "Run tests except system tests"
28
+ def perform(*args)
30
29
  $LOAD_PATH << Rails::Command.root.join("test").to_s
31
30
 
32
31
  Rails::TestUnit::Runner.parse_options(args)
32
+ run_prepare_task if self.args.none?(EXACT_TEST_ARGUMENT_PATTERN)
33
33
  Rails::TestUnit::Runner.run(args)
34
+ rescue Rails::TestUnit::InvalidTestError => error
35
+ raise ArgumentError, error.message
36
+ end
37
+
38
+ # Define Thor tasks to avoid going through Rake and booting twice when using bin/rails test:*
39
+ Rails::TestUnit::Runner::TEST_FOLDERS.each do |name|
40
+ desc name, "Run tests in test/#{name}"
41
+ define_method(name) do |*args|
42
+ perform("test/#{name}", *args)
43
+ end
44
+ end
45
+
46
+ desc "all", "Run all tests, including system tests"
47
+ def all(*args)
48
+ perform("test/**/*_test.rb", *args)
49
+ end
50
+
51
+ desc "functionals", "Run tests in test/controllers, test/mailers, and test/functional"
52
+ def functionals(*args)
53
+ perform("test/controllers", "test/mailers", "test/functional", *args)
54
+ end
55
+
56
+ desc "units", "Run tests in test/models, test/helpers, and test/unit"
57
+ def units(*args)
58
+ perform("test/models", "test/helpers", "test/unit", *args)
59
+ end
60
+
61
+ desc "system", "Run system tests only"
62
+ def system(*args)
63
+ perform("test/system", *args)
64
+ end
65
+
66
+ desc "generators", "Run tests in test/lib/generators"
67
+ def generators(*args)
68
+ perform("test/lib/generators", *args)
34
69
  end
70
+
71
+ private
72
+ EXACT_TEST_ARGUMENT_PATTERN = /^-n|^--name\b|#{Rails::TestUnit::Runner::PATH_ARGUMENT_PATTERN}/
73
+
74
+ def run_prepare_task
75
+ Rails::Command::RakeCommand.perform("test:prepare", [], {})
76
+ rescue UnrecognizedCommandError => error
77
+ raise unless error.name == "test:prepare"
78
+ end
35
79
  end
36
80
  end
37
81
  end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/commands/routes/routes_command"
4
+
5
+ module Rails
6
+ module Command
7
+ class UnusedRoutesCommand < Rails::Command::Base # :nodoc:
8
+ hide_command!
9
+ class_option :controller, aliases: "-c", desc: "Filter by a specific controller, e.g. PostsController or Admin::PostsController."
10
+ class_option :grep, aliases: "-g", desc: "Grep routes by a specific pattern."
11
+
12
+ class RouteInfo
13
+ def initialize(route)
14
+ requirements = route.requirements
15
+ @controller_name = requirements[:controller]
16
+ @action_name = requirements[:action]
17
+ @controller_class = (@controller_name.to_s.camelize + "Controller").safe_constantize
18
+ end
19
+
20
+ def unused?
21
+ controller_class_missing? || (action_missing? && template_missing?)
22
+ end
23
+
24
+ private
25
+ def view_path(root)
26
+ File.join(root.path, @controller_name, @action_name)
27
+ end
28
+
29
+ def controller_class_missing?
30
+ @controller_name && @controller_class.nil?
31
+ end
32
+
33
+ def template_missing?
34
+ @controller_class && @controller_class.try(:view_paths).to_a.flat_map { |path| Dir["#{view_path(path)}.*"] }.none?
35
+ end
36
+
37
+ def action_missing?
38
+ @controller_class && @controller_class.instance_methods.exclude?(@action_name.to_sym)
39
+ end
40
+ end
41
+
42
+ def perform(*)
43
+ boot_application!
44
+ require "action_dispatch/routing/inspector"
45
+
46
+ say(inspector.format(formatter, routes_filter))
47
+
48
+ exit(1) if routes.any?
49
+ end
50
+
51
+ private
52
+ def inspector
53
+ ActionDispatch::Routing::RoutesInspector.new(routes)
54
+ end
55
+
56
+ def routes
57
+ @routes ||= begin
58
+ routes = Rails.application.routes.routes.select do |route|
59
+ RouteInfo.new(route).unused?
60
+ end
61
+
62
+ ActionDispatch::Journey::Routes.new(routes)
63
+ end
64
+ end
65
+
66
+ def formatter
67
+ ActionDispatch::Routing::ConsoleFormatter::Unused.new
68
+ end
69
+
70
+ def routes_filter
71
+ options.symbolize_keys.slice(:controller, :grep)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -3,6 +3,7 @@
3
3
  module Rails
4
4
  module Command
5
5
  class VersionCommand < Base # :nodoc:
6
+ desc "version", "Show the Rails version"
6
7
  def perform
7
8
  Rails::Command.invoke :application, [ "--version" ]
8
9
  end
@@ -7,17 +7,17 @@ require "rails/rack"
7
7
 
8
8
  module Rails
9
9
  module Configuration
10
- # MiddlewareStackProxy is a proxy for the Rails middleware stack that allows
10
+ # MiddlewareStackProxy is a proxy for the \Rails middleware stack that allows
11
11
  # you to configure middlewares in your application. It works basically as a
12
12
  # command recorder, saving each command to be applied after initialization
13
13
  # over the default middleware stack, so you can add, swap, or remove any
14
- # middleware in Rails.
14
+ # middleware in \Rails.
15
15
  #
16
16
  # You can add your own middlewares by using the +config.middleware.use+ method:
17
17
  #
18
18
  # config.middleware.use Magical::Unicorns
19
19
  #
20
- # This will put the <tt>Magical::Unicorns</tt> middleware on the end of the stack.
20
+ # This will put the +Magical::Unicorns+ middleware on the end of the stack.
21
21
  # You can use +insert_before+ if you wish to add a middleware before another:
22
22
  #
23
23
  # config.middleware.insert_before Rack::Head, Magical::Unicorns
@@ -34,8 +34,8 @@ module Rails
34
34
  #
35
35
  # config.middleware.move_before ActionDispatch::Flash, Magical::Unicorns
36
36
  #
37
- # This will move the <tt>Magical::Unicorns</tt> middleware before the
38
- # <tt>ActionDispatch::Flash</tt>. You can also move it after:
37
+ # This will move the +Magical::Unicorns+ middleware before the
38
+ # +ActionDispatch::Flash+. You can also move it after:
39
39
  #
40
40
  # config.middleware.move_after ActionDispatch::Flash, Magical::Unicorns
41
41
  #
@@ -131,8 +131,17 @@ module Rails
131
131
  @after_generate_callbacks << block
132
132
  end
133
133
 
134
+ def apply_rubocop_autocorrect_after_generate!
135
+ after_generate do |files|
136
+ parsable_files = files.filter { |file| File.exist?(file) && file.end_with?(".rb") }
137
+ unless parsable_files.empty?
138
+ system(RbConfig.ruby, "bin/rubocop", "-A", "--fail-level=E", "--format=quiet", *parsable_files, exception: true)
139
+ end
140
+ end
141
+ end
142
+
134
143
  def method_missing(method, *args)
135
- method = method.to_s.delete_suffix("=").to_sym
144
+ method = method.name.delete_suffix("=").to_sym
136
145
 
137
146
  if args.empty?
138
147
  if method == :rails