railties 7.2.1.1 → 8.0.0.rc1

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +122 -278
  3. data/lib/minitest/rails_plugin.rb +1 -1
  4. data/lib/rails/application/bootstrap.rb +0 -1
  5. data/lib/rails/application/configuration.rb +15 -14
  6. data/lib/rails/application/default_middleware_stack.rb +4 -0
  7. data/lib/rails/application/finisher.rb +2 -3
  8. data/lib/rails/application/routes_reloader.rb +11 -1
  9. data/lib/rails/application.rb +5 -0
  10. data/lib/rails/code_statistics.rb +128 -86
  11. data/lib/rails/code_statistics_calculator.rb +78 -76
  12. data/lib/rails/command/helpers/editor.rb +1 -1
  13. data/lib/rails/command.rb +0 -6
  14. data/lib/rails/commands/app/update_command.rb +1 -9
  15. data/lib/rails/commands/console/irb_console.rb +11 -8
  16. data/lib/rails/commands/credentials/USAGE +4 -4
  17. data/lib/rails/commands/credentials/credentials_command.rb +5 -1
  18. data/lib/rails/commands/dev/dev_command.rb +1 -1
  19. data/lib/rails/commands/devcontainer/devcontainer_command.rb +2 -1
  20. data/lib/rails/commands/stats/stats_command.rb +19 -0
  21. data/lib/rails/console/methods.rb +5 -21
  22. data/lib/rails/dev_caching.rb +2 -2
  23. data/lib/rails/engine/configuration.rb +3 -1
  24. data/lib/rails/engine/lazy_route_set.rb +114 -0
  25. data/lib/rails/engine.rb +12 -8
  26. data/lib/rails/gem_version.rb +4 -4
  27. data/lib/rails/generators/app_base.rb +46 -28
  28. data/lib/rails/generators/base.rb +0 -4
  29. data/lib/rails/generators/database.rb +101 -67
  30. data/lib/rails/generators/erb/authentication/authentication_generator.rb +15 -0
  31. data/lib/rails/generators/erb/authentication/templates/app/views/passwords/edit.html.erb +9 -0
  32. data/lib/rails/generators/erb/authentication/templates/app/views/passwords/new.html.erb +8 -0
  33. data/lib/rails/generators/erb/authentication/templates/app/views/sessions/new.html.erb +11 -0
  34. data/lib/rails/generators/generated_attribute.rb +16 -11
  35. data/lib/rails/generators/rails/app/app_generator.rb +20 -32
  36. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +13 -4
  37. data/lib/rails/generators/rails/app/templates/Gemfile.tt +25 -10
  38. data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css.tt +6 -11
  39. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +10 -3
  40. data/lib/rails/generators/rails/app/templates/bin/dev.tt +1 -0
  41. data/lib/rails/generators/rails/app/templates/bin/setup.tt +5 -8
  42. data/lib/rails/generators/rails/app/templates/bin/thrust.tt +4 -0
  43. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +23 -0
  44. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +23 -0
  45. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +40 -0
  46. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +23 -0
  47. data/lib/rails/generators/rails/app/templates/config/deploy.yml.tt +128 -0
  48. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +12 -23
  49. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +34 -51
  50. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +5 -19
  51. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +0 -7
  52. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +1 -1
  53. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_0.rb.tt +25 -0
  54. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +11 -2
  55. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +3 -3
  56. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +4 -3
  57. data/lib/rails/generators/rails/app/templates/dockerignore.tt +1 -2
  58. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +5 -1
  59. data/lib/rails/generators/rails/app/templates/gitignore.tt +1 -2
  60. data/lib/rails/generators/rails/app/templates/kamal-secrets.tt +17 -0
  61. data/lib/rails/generators/rails/app/templates/public/400.html +114 -0
  62. data/lib/rails/generators/rails/app/templates/public/404.html +113 -66
  63. data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +113 -65
  64. data/lib/rails/generators/rails/app/templates/public/422.html +113 -66
  65. data/lib/rails/generators/rails/app/templates/public/500.html +113 -65
  66. data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
  67. data/lib/rails/generators/rails/app/templates/public/icon.svg +2 -2
  68. data/lib/rails/generators/rails/authentication/USAGE +6 -0
  69. data/lib/rails/generators/rails/authentication/authentication_generator.rb +56 -0
  70. data/lib/rails/generators/rails/authentication/templates/app/controllers/concerns/authentication.rb.tt +55 -0
  71. data/lib/rails/generators/rails/authentication/templates/app/controllers/passwords_controller.rb.tt +33 -0
  72. data/lib/rails/generators/rails/authentication/templates/app/controllers/sessions_controller.rb.tt +21 -0
  73. data/lib/rails/generators/rails/authentication/templates/app/mailers/passwords_mailer.rb.tt +6 -0
  74. data/lib/rails/generators/rails/authentication/templates/app/models/current.rb.tt +4 -0
  75. data/lib/rails/generators/rails/authentication/templates/app/models/session.rb.tt +3 -0
  76. data/lib/rails/generators/rails/authentication/templates/app/models/user.rb.tt +6 -0
  77. data/lib/rails/generators/rails/authentication/templates/app/views/passwords_mailer/reset.html.erb.tt +4 -0
  78. data/lib/rails/generators/rails/authentication/templates/app/views/passwords_mailer/reset.text.erb.tt +2 -0
  79. data/lib/rails/generators/rails/authentication/templates/test/mailers/previews/passwords_mailer_preview.rb.tt +7 -0
  80. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +4 -0
  81. data/lib/rails/generators/rails/db/system/change/change_generator.rb +1 -1
  82. data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +10 -3
  83. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +1 -1
  84. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +1 -1
  85. data/lib/rails/generators/rails/plugin/plugin_generator.rb +11 -11
  86. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +1 -1
  87. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +1 -1
  88. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +2 -2
  89. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +2 -2
  90. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +3 -3
  91. data/lib/rails/generators/rails/script/USAGE +18 -0
  92. data/lib/rails/generators/rails/script/script_generator.rb +18 -0
  93. data/lib/rails/generators/rails/script/templates/script.rb.tt +3 -0
  94. data/lib/rails/generators/test_unit/authentication/authentication_generator.rb +14 -0
  95. data/lib/rails/generators/test_unit/authentication/templates/test/fixtures/users.yml.tt +9 -0
  96. data/lib/rails/generators/test_unit/authentication/templates/test/models/user_test.rb.tt +7 -0
  97. data/lib/rails/generators.rb +7 -2
  98. data/lib/rails/info_controller.rb +10 -2
  99. data/lib/rails/rack/silence_request.rb +33 -0
  100. data/lib/rails/rack.rb +1 -0
  101. data/lib/rails/railtie.rb +13 -13
  102. data/lib/rails/source_annotation_extractor.rb +31 -14
  103. data/lib/rails/tasks/statistics.rake +13 -28
  104. data/lib/rails/templates/rails/info/notes.html.erb +65 -0
  105. data/lib/rails/test_unit/runner.rb +1 -0
  106. metadata +44 -23
  107. data/lib/rails/console/app.rb +0 -8
  108. data/lib/rails/console/helpers.rb +0 -8
  109. data/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt +0 -2
  110. data/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb.tt +0 -4
  111. data/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb.tt +0 -4
  112. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +0 -70
  113. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +0 -13
  114. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +0 -13
  115. data/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js.tt +0 -10
  116. data/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js.tt +0 -6
  117. data/lib/rails/generators/rails/plugin/templates/rails/javascripts.js.tt +0 -17
@@ -26,6 +26,9 @@ module Rails
26
26
  class_option :dev, type: :boolean, default: false,
27
27
  desc: "For applications pointing to a local Rails checkout"
28
28
 
29
+ class_option :kamal, type: :boolean, default: true,
30
+ desc: "Include configuration for Kamal"
31
+
29
32
  source_paths << File.expand_path(File.join(base_name, "app", "templates"), base_root)
30
33
 
31
34
  def create_devcontainer
@@ -38,9 +41,11 @@ module Rails
38
41
 
39
42
  def update_application_system_test_case
40
43
  return unless options[:system_test]
41
- return unless File.exist?("test/application_system_test_case.rb")
42
44
 
43
- gsub_file("test/application_system_test_case.rb", /^\s*driven_by\b.*/, system_test_configuration)
45
+ system_test_case_path = File.expand_path "test/application_system_test_case.rb", destination_root
46
+ return unless File.exist? system_test_case_path
47
+
48
+ gsub_file(system_test_case_path, /^\s*driven_by\b.*/, system_test_configuration)
44
49
  end
45
50
 
46
51
  def update_database_yml
@@ -78,6 +83,7 @@ module Rails
78
83
  @container_env["CAPYBARA_SERVER_PORT"] = "45678" if options[:system_test]
79
84
  @container_env["SELENIUM_HOST"] = "selenium" if options[:system_test]
80
85
  @container_env["REDIS_URL"] = "redis://redis:6379/1" if options[:redis]
86
+ @container_env["KAMAL_REGISTRY_PASSWORD"] = "$KAMAL_REGISTRY_PASSWORD" if options[:kamal]
81
87
  @container_env["DB_HOST"] = database.name if database.service
82
88
 
83
89
  @container_env
@@ -103,6 +109,7 @@ module Rails
103
109
 
104
110
  @features["ghcr.io/rails/devcontainer/features/activestorage"] = {} if options[:active_storage]
105
111
  @features["ghcr.io/devcontainers/features/node:1"] = {} if options[:node]
112
+ @features["ghcr.io/devcontainers/features/docker-outside-of-docker:1"] = {} if options[:kamal]
106
113
 
107
114
  @features.merge!(database.feature) if database.feature
108
115
 
@@ -148,7 +155,7 @@ module Rails
148
155
  end
149
156
 
150
157
  def system_test_configuration
151
- optimize_indentation(<<-'RUBY', 2)
158
+ optimize_indentation(<<-'RUBY', 2).chomp
152
159
  if ENV["CAPYBARA_SERVER_PORT"]
153
160
  served_by host: "rails-app", port: ENV["CAPYBARA_SERVER_PORT"]
154
161
 
@@ -1,3 +1,3 @@
1
1
  # Make sure RUBY_VERSION matches the Ruby version in .ruby-version
2
- ARG RUBY_VERSION=<%= gem_ruby_version %>
2
+ ARG RUBY_VERSION=<%= Gem.ruby_version %>
3
3
  FROM ghcr.io/rails/devcontainer/images/ruby:$RUBY_VERSION
@@ -33,5 +33,5 @@
33
33
  <%- end -%>
34
34
 
35
35
  // Use 'postCreateCommand' to run commands after the container is created.
36
- "postCreateCommand": "bin/setup"
36
+ "postCreateCommand": "bin/setup --skip-server"
37
37
  }
@@ -122,9 +122,12 @@ module Rails
122
122
  def generate_test_dummy(force = false)
123
123
  opts = options.transform_keys(&:to_sym).except(*DUMMY_IGNORE_OPTIONS)
124
124
  opts[:force] = force
125
+ opts[:skip_thruster] = true
125
126
  opts[:skip_brakeman] = true
126
127
  opts[:skip_bundle] = true
127
128
  opts[:skip_ci] = true
129
+ opts[:skip_kamal] = true
130
+ opts[:skip_solid] = true
128
131
  opts[:skip_git] = true
129
132
  opts[:skip_hotwire] = true
130
133
  opts[:skip_rubocop] = true
@@ -149,9 +152,8 @@ module Rails
149
152
  end
150
153
  end
151
154
 
152
- def test_dummy_sprocket_assets
153
- template "rails/stylesheets.css", "#{dummy_path}/app/assets/stylesheets/application.css", force: true
154
- template "rails/dummy_manifest.js", "#{dummy_path}/app/assets/config/manifest.js", force: true
155
+ def test_dummy_assets
156
+ template "rails/stylesheets.css", "#{dummy_path}/app/assets/stylesheets/application.css", force: true
155
157
  end
156
158
 
157
159
  def test_dummy_clean
@@ -159,7 +161,7 @@ module Rails
159
161
  remove_file ".ruby-version"
160
162
  remove_dir "db"
161
163
  remove_file "Gemfile"
162
- remove_file "lib/tasks"
164
+ remove_dir "lib"
163
165
  remove_file "public/robots.txt"
164
166
  remove_file "README.md"
165
167
  remove_file "test"
@@ -167,10 +169,6 @@ module Rails
167
169
  end
168
170
  end
169
171
 
170
- def assets_manifest
171
- template "rails/engine_manifest.js", "app/assets/config/#{underscored_name}_manifest.js"
172
- end
173
-
174
172
  def stylesheets
175
173
  if mountable?
176
174
  copy_file "rails/stylesheets.css",
@@ -361,7 +359,7 @@ module Rails
361
359
  mute do
362
360
  build(:generate_test_dummy)
363
361
  build(:test_dummy_config)
364
- build(:test_dummy_sprocket_assets) unless skip_sprockets?
362
+ build(:test_dummy_assets) unless skip_asset_pipeline?
365
363
  build(:test_dummy_clean)
366
364
  # ensure that bin/rails has proper dummy_path
367
365
  build(:bin)
@@ -491,9 +489,11 @@ module Rails
491
489
 
492
490
  def test_command
493
491
  if engine? && !options[:skip_active_record] && with_dummy_app?
494
- "db:test:prepare test"
492
+ "bin/rails db:test:prepare test"
493
+ elsif engine?
494
+ "bin/rails test"
495
495
  else
496
- "test"
496
+ "bin/test"
497
497
  end
498
498
  end
499
499
  end
@@ -19,5 +19,5 @@ gem "rubocop-rails-omakase", require: false
19
19
  <% end -%>
20
20
  <% if RUBY_PLATFORM.match?(/mingw|mswin|java/) -%>
21
21
 
22
- gem "tzinfo-data", platforms: %i[ <%= bundler_windows_platforms %> jruby ]
22
+ gem "tzinfo-data", platforms: %i[ windows jruby ]
23
23
  <% end -%>
@@ -90,7 +90,7 @@ jobs:
90
90
  DATABASE_URL: postgres://postgres:postgres@localhost:5432
91
91
  <%- end -%>
92
92
  # REDIS_URL: redis://localhost:6379/0
93
- run: bin/rails <%= test_command %>
93
+ run: <%= test_command %>
94
94
 
95
95
  - name: Keep screenshots from failed system tests
96
96
  uses: actions/upload-artifact@v4
@@ -3,7 +3,7 @@ ENV["RAILS_ENV"] = "test"
3
3
 
4
4
  require_relative "<%= File.join("..", options[:dummy_path], "config/environment") -%>"
5
5
  <% unless options[:skip_active_record] -%>
6
- ActiveRecord::Migrator.migrations_paths = [File.expand_path("../<%= options[:dummy_path] -%>/db/migrate", __dir__)]
6
+ ActiveRecord::Migrator.migrations_paths = [ File.expand_path("../<%= options[:dummy_path] -%>/db/migrate", __dir__) ]
7
7
  <% if options[:mountable] -%>
8
8
  ActiveRecord::Migrator.migrations_paths << File.expand_path("../db/migrate", __dir__)
9
9
  <% end -%>
@@ -13,7 +13,7 @@ require "rails/test_help"
13
13
  <% unless options[:skip_active_record] -%>
14
14
  # Load fixtures from the engine
15
15
  if ActiveSupport::TestCase.respond_to?(:fixture_paths=)
16
- ActiveSupport::TestCase.fixture_paths = [File.expand_path("fixtures", __dir__)]
16
+ ActiveSupport::TestCase.fixture_paths = [ File.expand_path("fixtures", __dir__) ]
17
17
  ActionDispatch::IntegrationTest.fixture_paths = ActiveSupport::TestCase.fixture_paths
18
18
  ActiveSupport::TestCase.file_fixture_path = File.expand_path("fixtures", __dir__) + "/files"
19
19
  ActiveSupport::TestCase.fixtures :all
@@ -42,7 +42,7 @@ class <%= controller_class_name %>Controller < ApplicationController
42
42
  private
43
43
  # Use callbacks to share common setup or constraints between actions.
44
44
  def set_<%= singular_table_name %>
45
- @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
45
+ @<%= singular_table_name %> = <%= orm_class.find(class_name, "params.expect(:id)") %>
46
46
  end
47
47
 
48
48
  # Only allow a list of trusted parameters through.
@@ -50,7 +50,7 @@ class <%= controller_class_name %>Controller < ApplicationController
50
50
  <%- if attributes_names.empty? -%>
51
51
  params.fetch(:<%= singular_table_name %>, {})
52
52
  <%- else -%>
53
- params.require(:<%= singular_table_name %>).permit(<%= permitted_params %>)
53
+ params.expect(<%= singular_table_name %>: [ <%= permitted_params %> ])
54
54
  <%- end -%>
55
55
  end
56
56
  end
@@ -43,13 +43,13 @@ class <%= controller_class_name %>Controller < ApplicationController
43
43
  # DELETE <%= route_url %>/1
44
44
  def destroy
45
45
  @<%= orm_instance.destroy %>
46
- redirect_to <%= index_helper %>_url, notice: <%= %("#{human_name} was successfully destroyed.") %>, status: :see_other
46
+ redirect_to <%= index_helper %>_path, notice: <%= %("#{human_name} was successfully destroyed.") %>, status: :see_other
47
47
  end
48
48
 
49
49
  private
50
50
  # Use callbacks to share common setup or constraints between actions.
51
51
  def set_<%= singular_table_name %>
52
- @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
52
+ @<%= singular_table_name %> = <%= orm_class.find(class_name, "params.expect(:id)") %>
53
53
  end
54
54
 
55
55
  # Only allow a list of trusted parameters through.
@@ -57,7 +57,7 @@ class <%= controller_class_name %>Controller < ApplicationController
57
57
  <%- if attributes_names.empty? -%>
58
58
  params.fetch(:<%= singular_table_name %>, {})
59
59
  <%- else -%>
60
- params.require(:<%= singular_table_name %>).permit(<%= permitted_params %>)
60
+ params.expect(<%= singular_table_name %>: [ <%= permitted_params %> ])
61
61
  <%- end -%>
62
62
  end
63
63
  end
@@ -0,0 +1,18 @@
1
+ Description:
2
+ Generate a one-off or general purpose script, such as a data migration
3
+ script, cleanup script, etc.
4
+
5
+ Example:
6
+ `bin/rails generate script my_script`
7
+
8
+ This will create:
9
+ script/my_script.rb
10
+
11
+ You can run the script using:
12
+ `ruby script/my_script.rb`
13
+
14
+ You can specify a folder:
15
+ `bin/rails generate script cleanup/my_script`
16
+
17
+ This will create:
18
+ script/cleanup/my_script.rb
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/named_base"
4
+
5
+ module Rails
6
+ module Generators
7
+ class ScriptGenerator < NamedBase
8
+ def generate_script
9
+ template("script.rb.tt", "script/#{file_path}.rb")
10
+ end
11
+
12
+ private
13
+ def depth
14
+ class_path.size + 1
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ require_relative "<%= '../' * depth %>config/environment"
2
+
3
+ # Your code goes here
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/test_unit"
4
+
5
+ module TestUnit # :nodoc:
6
+ module Generators # :nodoc:
7
+ class AuthenticationGenerator < Rails::Generators::Base # :nodoc:
8
+ def create_user_test_files
9
+ template "test/fixtures/users.yml"
10
+ template "test/models/user_test.rb"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ <%% password_digest = BCrypt::Password.create("password") %>
2
+
3
+ one:
4
+ email_address: one@example.com
5
+ password_digest: <%%= password_digest %>
6
+
7
+ two:
8
+ email_address: two@example.com
9
+ password_digest: <%%= password_digest %>
@@ -0,0 +1,7 @@
1
+ require "test_helper"
2
+
3
+ class UserTest < ActiveSupport::TestCase
4
+ # test "the truth" do
5
+ # assert true
6
+ # end
7
+ end
@@ -23,7 +23,6 @@ module Rails
23
23
  autoload :NamedBase, "rails/generators/named_base"
24
24
  autoload :ResourceHelpers, "rails/generators/resource_helpers"
25
25
  autoload :TestCase, "rails/generators/test_case"
26
- autoload :Devcontainer, "rails/generators/devcontainer"
27
26
 
28
27
  mattr_accessor :namespace
29
28
 
@@ -61,6 +60,10 @@ module Rails
61
60
  }
62
61
  }
63
62
 
63
+ # We need to store the RAILS_DEV_PATH in a constant, otherwise the path
64
+ # can change when we FileUtils.cd.
65
+ RAILS_DEV_PATH = File.expand_path("../../..", __dir__) # :nodoc:
66
+
64
67
  class << self
65
68
  def configure!(config) # :nodoc:
66
69
  api_only! if config.api_only
@@ -152,7 +155,8 @@ module Rails
152
155
  "#{template}:scaffold",
153
156
  "#{template}:mailer",
154
157
  "action_text:install",
155
- "action_mailbox:install"
158
+ "action_mailbox:install",
159
+ "devcontainer"
156
160
  ]
157
161
  end
158
162
  end
@@ -268,6 +272,7 @@ module Rails
268
272
  #{error.detailed_message}
269
273
  Run `bin/rails generate --help` for more options.
270
274
  MSG
275
+ exit 1
271
276
  end
272
277
  end
273
278
 
@@ -20,7 +20,7 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc:
20
20
 
21
21
  def routes
22
22
  if query = params[:query]
23
- query = URI::DEFAULT_PARSER.escape query
23
+ query = URI::RFC2396_PARSER.escape query
24
24
 
25
25
  render json: {
26
26
  exact: matching_routes(query: query, exact_match: true),
@@ -32,6 +32,14 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc:
32
32
  end
33
33
  end
34
34
 
35
+ def notes
36
+ @annotations = Rails::SourceAnnotationExtractor.new(
37
+ Rails::SourceAnnotationExtractor::Annotation.tags.join("|")
38
+ ).find(
39
+ Rails::SourceAnnotationExtractor::Annotation.directories
40
+ )
41
+ end
42
+
35
43
  private
36
44
  def matching_routes(query:, exact_match:)
37
45
  return [] if query.blank?
@@ -53,7 +61,7 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc:
53
61
  match ||= (query === route_wrapper.verb)
54
62
 
55
63
  unless match
56
- controller_action = URI::DEFAULT_PARSER.escape(route_wrapper.reqs)
64
+ controller_action = URI::RFC2396_PARSER.escape(route_wrapper.reqs)
57
65
  match = exact_match ? (query === controller_action) : controller_action.include?(query)
58
66
  end
59
67
 
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "active_support/logger_silence"
6
+
7
+ module Rails
8
+ module Rack
9
+ # Allows you to silence requests made to a specific path.
10
+ # This is useful for preventing recurring requests like health checks from clogging the logging.
11
+ # This middleware is used to do just that against the path /up in production by default.
12
+ #
13
+ # Example:
14
+ #
15
+ # config.middleware.insert_before \
16
+ # Rails::Rack::Logger, Rails::Rack::SilenceRequest, path: "/up"
17
+ #
18
+ # This middleware can also be configured using `config.silence_healthcheck_path = "/up"` in Rails.
19
+ class SilenceRequest
20
+ def initialize(app, path:)
21
+ @app, @path = app, path
22
+ end
23
+
24
+ def call(env)
25
+ if env["PATH_INFO"] == @path
26
+ Rails.logger.silence { @app.call(env) }
27
+ else
28
+ @app.call(env)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
data/lib/rails/rack.rb CHANGED
@@ -3,5 +3,6 @@
3
3
  module Rails
4
4
  module Rack
5
5
  autoload :Logger, "rails/rack/logger"
6
+ autoload :SilenceRequest, "rails/rack/silence_request"
6
7
  end
7
8
  end
data/lib/rails/railtie.rb CHANGED
@@ -50,8 +50,8 @@ module Rails
50
50
  # To add an initialization step to the \Rails boot process from your railtie, just
51
51
  # define the initialization code with the +initializer+ macro:
52
52
  #
53
- # class MyRailtie < Rails::Railtie
54
- # initializer "my_railtie.configure_rails_initialization" do
53
+ # class MyGem::Railtie < Rails::Railtie
54
+ # initializer "my_gem.configure_rails_initialization" do
55
55
  # # some initialization behavior
56
56
  # end
57
57
  # end
@@ -59,9 +59,9 @@ module Rails
59
59
  # If specified, the block can also receive the application object, in case you
60
60
  # need to access some application-specific configuration, like middleware:
61
61
  #
62
- # class MyRailtie < Rails::Railtie
63
- # initializer "my_railtie.configure_rails_initialization" do |app|
64
- # app.middleware.use MyRailtie::Middleware
62
+ # class MyGem::Railtie < Rails::Railtie
63
+ # initializer "my_gem.configure_rails_initialization" do |app|
64
+ # app.middleware.use MyGem::Middleware
65
65
  # end
66
66
  # end
67
67
  #
@@ -74,14 +74,14 @@ module Rails
74
74
  # Railties can access a config object which contains configuration shared by all
75
75
  # railties and the application:
76
76
  #
77
- # class MyRailtie < Rails::Railtie
77
+ # class MyGem::Railtie < Rails::Railtie
78
78
  # # Customize the ORM
79
- # config.app_generators.orm :my_railtie_orm
79
+ # config.app_generators.orm :my_gem_orm
80
80
  #
81
81
  # # Add a to_prepare block which is executed once in production
82
82
  # # and before each request in development.
83
83
  # config.to_prepare do
84
- # MyRailtie.setup!
84
+ # MyGem.setup!
85
85
  # end
86
86
  # end
87
87
  #
@@ -90,9 +90,9 @@ module Rails
90
90
  # If your railtie has Rake tasks, you can tell \Rails to load them through the method
91
91
  # +rake_tasks+:
92
92
  #
93
- # class MyRailtie < Rails::Railtie
93
+ # class MyGem::Railtie < Rails::Railtie
94
94
  # rake_tasks do
95
- # load "path/to/my_railtie.tasks"
95
+ # load "path/to/my_gem.tasks"
96
96
  # end
97
97
  # end
98
98
  #
@@ -100,9 +100,9 @@ module Rails
100
100
  # your generators at a different location, you can specify in your railtie a block which
101
101
  # will load them during normal generators lookup:
102
102
  #
103
- # class MyRailtie < Rails::Railtie
103
+ # class MyGem::Railtie < Rails::Railtie
104
104
  # generators do
105
- # require "path/to/my_railtie_generator"
105
+ # require "path/to/my_gem_generator"
106
106
  # end
107
107
  # end
108
108
  #
@@ -120,7 +120,7 @@ module Rails
120
120
  # this less confusing for everyone.
121
121
  # It can be used like this:
122
122
  #
123
- # class MyRailtie < Rails::Railtie
123
+ # class MyGem::Railtie < Rails::Railtie
124
124
  # server do
125
125
  # WebpackServer.start
126
126
  # end
@@ -1,6 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "ripper"
3
+ begin
4
+ require "prism"
5
+ rescue LoadError
6
+ # If Prism isn't available (because of using an older Ruby version) then we'll
7
+ # define a fallback for the ParserExtractor using ripper.
8
+ require "ripper"
9
+ end
4
10
 
5
11
  module Rails
6
12
  # Implements the logic behind +Rails::Command::NotesCommand+. See <tt>rails notes --help</tt> for usage information.
@@ -16,24 +22,35 @@ module Rails
16
22
  # Wraps a regular expression that will be tested against each of the source
17
23
  # file's comments.
18
24
  class ParserExtractor < Struct.new(:pattern)
19
- class Parser < Ripper
20
- attr_reader :comments, :pattern
25
+ if defined?(Prism)
26
+ def annotations(file)
27
+ result = Prism.parse_file(file)
28
+ return [] unless result.success?
21
29
 
22
- def initialize(source, pattern:)
23
- super(source)
24
- @pattern = pattern
25
- @comments = []
30
+ result.comments.filter_map do |comment|
31
+ Annotation.new(comment.location.start_line, $1, $2) if comment.location.slice =~ pattern
32
+ end
26
33
  end
34
+ else
35
+ class Parser < Ripper
36
+ attr_reader :comments, :pattern
37
+
38
+ def initialize(source, pattern:)
39
+ super(source)
40
+ @pattern = pattern
41
+ @comments = []
42
+ end
27
43
 
28
- def on_comment(value)
29
- @comments << Annotation.new(lineno, $1, $2) if value =~ pattern
44
+ def on_comment(value)
45
+ @comments << Annotation.new(lineno, $1, $2) if value =~ pattern
46
+ end
30
47
  end
31
- end
32
48
 
33
- def annotations(file)
34
- contents = File.read(file, encoding: Encoding::BINARY)
35
- parser = Parser.new(contents, pattern: pattern).tap(&:parse)
36
- parser.error? ? [] : parser.comments
49
+ def annotations(file)
50
+ contents = File.read(file, encoding: Encoding::BINARY)
51
+ parser = Parser.new(contents, pattern: pattern).tap(&:parse)
52
+ parser.error? ? [] : parser.comments
53
+ end
37
54
  end
38
55
  end
39
56
 
@@ -1,32 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # While global constants are bad, many 3rd party tools depend on this one (e.g
4
- # rspec-rails & cucumber-rails). So a deprecation warning is needed if we want
5
- # to remove it.
6
- STATS_DIRECTORIES ||= [
7
- %w(Controllers app/controllers),
8
- %w(Helpers app/helpers),
9
- %w(Jobs app/jobs),
10
- %w(Models app/models),
11
- %w(Mailers app/mailers),
12
- %w(Mailboxes app/mailboxes),
13
- %w(Channels app/channels),
14
- %w(Views app/views),
15
- %w(JavaScripts app/assets/javascripts),
16
- %w(Stylesheets app/assets/stylesheets),
17
- %w(JavaScript app/javascript),
18
- %w(Libraries lib/),
19
- %w(APIs app/apis),
20
- %w(Controller\ tests test/controllers),
21
- %w(Helper\ tests test/helpers),
22
- %w(Job\ tests test/jobs),
23
- %w(Model\ tests test/models),
24
- %w(Mailer\ tests test/mailers),
25
- %w(Mailbox\ tests test/mailboxes),
26
- %w(Channel\ tests test/channels),
27
- %w(Integration\ tests test/integration),
28
- %w(System\ tests test/system),
29
- ]
3
+ require "rails/code_statistics"
4
+ STATS_DIRECTORIES = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
5
+ Rails::CodeStatistics::DIRECTORIES,
6
+ "`STATS_DIRECTORIES` is deprecated and will be removed in Rails 8.1! Use `Rails::CodeStatistics.register_directory('My Directory', 'path/to/dir)` instead.",
7
+ Rails.deprecator
8
+ )
30
9
 
31
10
  desc "Report code statistics (KLOCs, etc) from the application or engine"
32
11
  task :stats do
@@ -34,5 +13,11 @@ task :stats do
34
13
  stat_directories = STATS_DIRECTORIES.collect do |name, dir|
35
14
  [ name, "#{File.dirname(Rake.application.rakefile_location)}/#{dir}" ]
36
15
  end.select { |name, dir| File.directory?(dir) }
37
- CodeStatistics.new(*stat_directories).to_s
16
+
17
+ $stderr.puts Rails.deprecator.warn(<<~MSG, caller_locations(0..1))
18
+ `bin/rake stats` has been deprecated and will be removed in Rails 8.1.
19
+ Please use `bin/rails stats` as Rails command instead.\n
20
+ MSG
21
+
22
+ Rails::CodeStatistics.new(*stat_directories).to_s
38
23
  end
@@ -0,0 +1,65 @@
1
+ <style>
2
+ h2, p {
3
+ padding-left: 30px;
4
+ }
5
+ table {
6
+ margin: 0;
7
+ border-collapse: collapse;
8
+ word-wrap:break-word;
9
+ table-layout: fixed;
10
+ width:100%;
11
+ }
12
+ table thead tr {
13
+ border-bottom: 2px solid #ddd;
14
+ }
15
+ table th {
16
+ padding-left: 30px;
17
+ text-align: left;
18
+ }
19
+ table thead th.tag, table thead th.line-no {
20
+ width: 10%;
21
+ }
22
+ table tbody tr {
23
+ border-bottom: 1px solid #ddd;
24
+ }
25
+ table tbody tr:nth-child(odd) {
26
+ background: #f2f2f2;
27
+ }
28
+ table td {
29
+ padding: 4px 30px;
30
+ }
31
+ @media (prefers-color-scheme: dark) {
32
+ table tbody tr:nth-child(odd) {
33
+ background: #282828;
34
+ }
35
+ }
36
+ </style>
37
+
38
+ <h2>
39
+ Notes
40
+ </h2>
41
+
42
+ <table id="route_table" class="table">
43
+ <thead>
44
+ <th>File Name</th>
45
+ <th class="line-no">Line No.</th>
46
+ <th class="tag">Tag</th>
47
+ <th>Description</th>
48
+ </thead>
49
+ <tbody>
50
+ <% @annotations.each do |file, annotations| %>
51
+ <% annotations.each.with_index do |annotation, index| %>
52
+ <tr>
53
+ <% if index == 0 %>
54
+ <th rowspan="<%= annotations.size %>">
55
+ <%= file %>
56
+ </th>
57
+ <% end %>
58
+ <td class="line-no"><%= annotation.line %></td>
59
+ <td class="tag"><%= annotation.tag %></td>
60
+ <td><%= annotation.text %></td>
61
+ </tr>
62
+ <% end %>
63
+ <% end %>
64
+ </tbody>
65
+ </table>
@@ -125,6 +125,7 @@ module Rails
125
125
  def list_tests(patterns)
126
126
  tests = Rake::FileList[patterns.any? ? patterns : default_test_glob]
127
127
  tests.exclude(default_test_exclude_glob) if patterns.empty?
128
+ tests.exclude(%r{test/isolation/assets/node_modules})
128
129
  tests
129
130
  end
130
131