railties 7.1.3.4 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +177 -742
  3. data/lib/minitest/rails_plugin.rb +5 -2
  4. data/lib/rails/all.rb +1 -3
  5. data/lib/rails/api/task.rb +6 -4
  6. data/lib/rails/application/bootstrap.rb +5 -6
  7. data/lib/rails/application/configuration.rb +73 -38
  8. data/lib/rails/application/dummy_config.rb +2 -2
  9. data/lib/rails/application/finisher.rb +7 -0
  10. data/lib/rails/application.rb +15 -86
  11. data/lib/rails/backtrace_cleaner.rb +18 -3
  12. data/lib/rails/cli.rb +0 -1
  13. data/lib/rails/command.rb +1 -1
  14. data/lib/rails/commands/app/update_command.rb +93 -0
  15. data/lib/rails/commands/boot/boot_command.rb +14 -0
  16. data/lib/rails/commands/console/console_command.rb +2 -21
  17. data/lib/rails/commands/console/irb_console.rb +137 -0
  18. data/lib/rails/commands/credentials/credentials_command.rb +2 -2
  19. data/lib/rails/commands/dbconsole/dbconsole_command.rb +21 -30
  20. data/lib/rails/commands/devcontainer/devcontainer_command.rb +39 -0
  21. data/lib/rails/commands/rake/rake_command.rb +1 -1
  22. data/lib/rails/commands/runner/runner_command.rb +14 -3
  23. data/lib/rails/commands/server/server_command.rb +5 -3
  24. data/lib/rails/commands/test/test_command.rb +2 -0
  25. data/lib/rails/configuration.rb +10 -1
  26. data/lib/rails/console/app.rb +5 -32
  27. data/lib/rails/console/helpers.rb +5 -16
  28. data/lib/rails/console/methods.rb +23 -0
  29. data/lib/rails/engine.rb +5 -5
  30. data/lib/rails/gem_version.rb +3 -3
  31. data/lib/rails/generators/app_base.rb +70 -49
  32. data/lib/rails/generators/base.rb +5 -1
  33. data/lib/rails/generators/database.rb +227 -69
  34. data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +2 -0
  35. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +2 -0
  36. data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +2 -0
  37. data/lib/rails/generators/generated_attribute.rb +26 -1
  38. data/lib/rails/generators/migration.rb +3 -3
  39. data/lib/rails/generators/rails/app/app_generator.rb +53 -24
  40. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +22 -15
  41. data/lib/rails/generators/rails/app/templates/Gemfile.tt +16 -16
  42. data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +4 -0
  43. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +8 -1
  44. data/lib/rails/generators/rails/app/templates/app/views/pwa/manifest.json.erb.tt +22 -0
  45. data/lib/rails/generators/rails/app/templates/app/views/pwa/service-worker.js +26 -0
  46. data/lib/rails/generators/rails/app/templates/bin/brakeman.tt +6 -0
  47. data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +7 -0
  48. data/lib/rails/generators/rails/app/templates/bin/setup.tt +6 -2
  49. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +1 -1
  50. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +3 -3
  51. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +7 -0
  52. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +8 -1
  53. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +3 -3
  54. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +14 -7
  55. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +5 -0
  56. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +8 -5
  57. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +1 -1
  58. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +70 -0
  59. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +24 -26
  60. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +4 -0
  61. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +5 -0
  62. data/lib/rails/generators/rails/app/templates/dockerignore.tt +13 -0
  63. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +138 -0
  64. data/lib/rails/generators/rails/app/templates/github/dependabot.yml +12 -0
  65. data/lib/rails/generators/rails/app/templates/gitignore.tt +3 -3
  66. data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +66 -0
  67. data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
  68. data/lib/rails/generators/rails/app/templates/public/icon.svg +3 -0
  69. data/lib/rails/generators/rails/app/templates/rubocop.yml.tt +8 -0
  70. data/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt +1 -1
  71. data/lib/rails/generators/rails/controller/controller_generator.rb +1 -1
  72. data/lib/rails/generators/rails/db/system/change/change_generator.rb +131 -20
  73. data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +166 -0
  74. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +3 -0
  75. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/compose.yaml.tt +47 -0
  76. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +37 -0
  77. data/lib/rails/generators/rails/migration/migration_generator.rb +4 -0
  78. data/lib/rails/generators/rails/plugin/plugin_generator.rb +38 -7
  79. data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +2 -2
  80. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +5 -1
  81. data/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +2 -0
  82. data/lib/rails/generators/rails/plugin/templates/bin/rubocop.tt +7 -0
  83. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +103 -0
  84. data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +12 -0
  85. data/lib/rails/generators/rails/plugin/templates/rubocop.yml.tt +8 -0
  86. data/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt +1 -1
  87. data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb.tt +6 -4
  88. data/lib/rails/generators/test_unit/mailer/templates/preview.rb.tt +3 -2
  89. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +15 -1
  90. data/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt +2 -2
  91. data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +2 -2
  92. data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +2 -0
  93. data/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt +1 -1
  94. data/lib/rails/generators/testing/assertions.rb +20 -0
  95. data/lib/rails/generators/testing/behavior.rb +7 -6
  96. data/lib/rails/generators.rb +1 -1
  97. data/lib/rails/health_controller.rb +1 -1
  98. data/lib/rails/info.rb +2 -2
  99. data/lib/rails/mailers_controller.rb +14 -1
  100. data/lib/rails/paths.rb +2 -2
  101. data/lib/rails/pwa_controller.rb +15 -0
  102. data/lib/rails/rack/logger.rb +15 -7
  103. data/lib/rails/railtie/configurable.rb +2 -2
  104. data/lib/rails/railtie.rb +2 -3
  105. data/lib/rails/tasks/framework.rake +0 -26
  106. data/lib/rails/tasks/tmp.rake +1 -1
  107. data/lib/rails/templates/layouts/application.html.erb +1 -1
  108. data/lib/rails/templates/rails/mailers/email.html.erb +12 -8
  109. data/lib/rails/templates/rails/welcome/index.html.erb +4 -2
  110. data/lib/rails/test_help.rb +2 -4
  111. data/lib/rails/test_unit/reporter.rb +8 -2
  112. data/lib/rails/test_unit/runner.rb +26 -2
  113. data/lib/rails/test_unit/test_parser.rb +45 -0
  114. data/lib/rails.rb +7 -4
  115. metadata +42 -32
  116. data/lib/rails/app_updater.rb +0 -40
  117. data/lib/rails/commands/secrets/USAGE +0 -61
  118. data/lib/rails/commands/secrets/secrets_command.rb +0 -47
  119. data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +0 -68
  120. data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt +0 -54
  121. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +0 -70
  122. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +0 -24
  123. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +0 -62
  124. data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +0 -53
  125. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_1.rb.tt +0 -284
  126. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon-precomposed.png +0 -0
  127. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon.png +0 -0
  128. data/lib/rails/generators/rails/app/templates/public/favicon.ico +0 -0
  129. data/lib/rails/ruby_version_check.rb +0 -17
  130. data/lib/rails/secrets.rb +0 -110
@@ -1,5 +1,5 @@
1
1
  require "test_helper"
2
2
 
3
3
  class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
4
- driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
4
+ driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ]
5
5
  end
@@ -121,6 +121,26 @@ module Rails
121
121
  assert_equal(value, create_generated_attribute(attribute_type).default)
122
122
  end
123
123
  end
124
+
125
+ # Asserts a given initializer exists. You need to supply a path relative
126
+ # to the `config/initializers/` directory.
127
+ #
128
+ # assert_initializer "mail_interceptors.rb"
129
+ #
130
+ # You can also give extra arguments. If the argument is a regexp, it will check if the
131
+ # regular expression matches the given file content. If it's a string, it compares the
132
+ # file with the given string:
133
+ #
134
+ # assert_initializer "mail_interceptors.rb", /SandboxEmailInterceptor/
135
+ #
136
+ # Finally, when a block is given, it yields the file content:
137
+ #
138
+ # assert_initializer "mail_interceptors.rb" do |initializer|
139
+ # assert_match(/SandboxEmailInterceptor/, initializer)
140
+ # end
141
+ def assert_initializer(name, *contents, &block)
142
+ assert_file("config/initializers/#{name}", *contents, &block)
143
+ end
124
144
  end
125
145
  end
126
146
  end
@@ -65,11 +65,15 @@ module Rails
65
65
  # You can provide a configuration hash as second argument. This method returns the output
66
66
  # printed by the generator.
67
67
  def run_generator(args = default_arguments, config = {})
68
- capture(:stdout) do
69
- args += ["--skip-bundle"] unless args.include?("--no-skip-bundle") || args.include?("--dev")
70
- args += ["--skip-bootsnap"] unless args.include?("--no-skip-bootsnap") || args.include?("--skip-bootsnap")
68
+ args += ["--skip-bundle"] unless args.include?("--no-skip-bundle") || args.include?("--dev")
69
+ args += ["--skip-bootsnap"] unless args.include?("--no-skip-bootsnap") || args.include?("--skip-bootsnap")
71
70
 
71
+ if ENV["RAILS_LOG_TO_STDOUT"] == "true"
72
72
  generator_class.start(args, config.reverse_merge(destination_root: destination_root))
73
+ else
74
+ capture(:stdout) do
75
+ generator_class.start(args, config.reverse_merge(destination_root: destination_root))
76
+ end
73
77
  end
74
78
  end
75
79
 
@@ -107,9 +111,6 @@ module Rails
107
111
  Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
108
112
  end
109
113
  end
110
-
111
- include ActiveSupport::Deprecation::DeprecatedConstantAccessor
112
- deprecate_constant "Behaviour", "Rails::Generators::Testing::Behavior", deprecator: Rails.deprecator
113
114
  end
114
115
  end
115
116
  end
@@ -23,6 +23,7 @@ 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"
26
27
 
27
28
  mattr_accessor :namespace
28
29
 
@@ -202,7 +203,6 @@ module Rails
202
203
  rails.map! { |n| n.delete_prefix("rails:") }
203
204
  rails.delete("app")
204
205
  rails.delete("plugin")
205
- rails.delete("encrypted_secrets")
206
206
  rails.delete("encrypted_file")
207
207
  rails.delete("encryption_key_file")
208
208
  rails.delete("master_key")
@@ -24,7 +24,7 @@ module Rails
24
24
  # The health check will now be accessible via the +/healthz+ path.
25
25
  #
26
26
  # NOTE: This endpoint does not reflect the status of all of your application's
27
- # dependencies, such as the database or redis cluster. Replace
27
+ # dependencies, such as the database or Redis cluster. Replace
28
28
  # <tt>"rails/health#show"</tt> with your own controller action if you have
29
29
  # application specific needs.
30
30
  #
data/lib/rails/info.rb CHANGED
@@ -95,11 +95,11 @@ module Rails
95
95
 
96
96
  # The name of the database adapter for the current environment.
97
97
  property "Database adapter" do
98
- ActiveRecord::Base.connection.pool.db_config.adapter
98
+ ActiveRecord::Base.connection_pool.db_config.adapter
99
99
  end
100
100
 
101
101
  property "Database schema version" do
102
- ActiveRecord::Base.connection.migration_context.current_version rescue nil
102
+ ActiveRecord::Base.connection_pool.migration_context.current_version rescue nil
103
103
  end
104
104
  end
105
105
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rails/application_controller"
4
+ require "active_support/core_ext/enumerable"
4
5
 
5
6
  class Rails::MailersController < Rails::ApplicationController # :nodoc:
6
7
  prepend_view_path ActionDispatch::DebugView::RESCUES_TEMPLATE_PATHS
@@ -9,7 +10,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
9
10
  before_action :find_preview, only: [:preview, :download]
10
11
  before_action :require_local!, unless: :show_previews?
11
12
 
12
- helper_method :part_query, :locale_query
13
+ helper_method :attachment_url, :part_query, :locale_query
13
14
 
14
15
  content_security_policy(false)
15
16
 
@@ -38,6 +39,8 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
38
39
  if @preview.email_exists?(@email_action)
39
40
  @page_title = "Mailer Preview for #{@preview.preview_name}##{@email_action}"
40
41
  @email = @preview.call(@email_action, params)
42
+ @attachments = attachments_for(@email).reject { |filename, attachment| attachment.inline? }
43
+ @inline_attachments = attachments_for(@email).select { |filename, attachment| attachment.inline? }
41
44
 
42
45
  if params[:part]
43
46
  part_type = Mime::Type.lookup(params[:part])
@@ -95,6 +98,16 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
95
98
  end
96
99
  end
97
100
 
101
+ def attachments_for(email)
102
+ email.all_parts.to_a.select(&:attachment?).index_by do |attachment|
103
+ attachment.respond_to?(:original_filename) ? attachment.original_filename : attachment.filename
104
+ end
105
+ end
106
+
107
+ def attachment_url(attachment)
108
+ "data:application/octet-stream;charset=utf-8;base64,#{Base64.encode64(attachment.body.to_s)}"
109
+ end
110
+
98
111
  def part_query(mime_type)
99
112
  request.query_parameters.merge(part: mime_type).to_query
100
113
  end
data/lib/rails/paths.rb CHANGED
@@ -105,8 +105,8 @@ module Rails
105
105
  private
106
106
  def filter_by(&block)
107
107
  all_paths.find_all(&block).flat_map { |path|
108
- paths = path.existent
109
- paths - path.children.flat_map { |p| yield(p) ? [] : p.existent }
108
+ paths = path.existent_directories
109
+ paths - path.children.flat_map { |p| yield(p) ? [] : p.existent_directories }
110
110
  }.uniq
111
111
  end
112
112
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/application_controller"
4
+
5
+ class Rails::PwaController < Rails::ApplicationController # :nodoc:
6
+ skip_forgery_protection
7
+
8
+ def service_worker
9
+ render template: "pwa/service-worker", layout: false
10
+ end
11
+
12
+ def manifest
13
+ render template: "pwa/manifest", layout: false
14
+ end
15
+ end
@@ -20,22 +20,26 @@ module Rails
20
20
  def call(env)
21
21
  request = ActionDispatch::Request.new(env)
22
22
 
23
- if logger.respond_to?(:tagged)
24
- logger.tagged(*compute_tags(request)) { call_app(request, env) }
23
+ env["rails.rack_logger_tag_count"] = if logger.respond_to?(:push_tags)
24
+ logger.push_tags(*compute_tags(request)).size
25
25
  else
26
- call_app(request, env)
26
+ 0
27
27
  end
28
+
29
+ call_app(request, env)
28
30
  end
29
31
 
30
32
  private
31
33
  def call_app(request, env) # :doc:
34
+ logger_tag_pop_count = env["rails.rack_logger_tag_count"]
35
+
32
36
  instrumenter = ActiveSupport::Notifications.instrumenter
33
37
  handle = instrumenter.build_handle("request.action_dispatch", { request: request })
34
38
  handle.start
35
39
 
36
40
  logger.info { started_request_message(request) }
37
41
  status, headers, body = response = @app.call(env)
38
- body = ::Rack::BodyProxy.new(body, &handle.method(:finish))
42
+ body = ::Rack::BodyProxy.new(body) { finish_request_instrumentation(handle, logger_tag_pop_count) }
39
43
 
40
44
  if response.frozen?
41
45
  [status, headers, body]
@@ -44,10 +48,8 @@ module Rails
44
48
  response
45
49
  end
46
50
  rescue Exception
47
- handle.finish
51
+ finish_request_instrumentation(handle, logger_tag_pop_count)
48
52
  raise
49
- ensure
50
- ActiveSupport::LogSubscriber.flush_all!
51
53
  end
52
54
 
53
55
  # Started GET "/session/new" for 127.0.0.1 at 2012-09-26 14:51:42 -0700
@@ -75,6 +77,12 @@ module Rails
75
77
  def logger
76
78
  Rails.logger
77
79
  end
80
+
81
+ def finish_request_instrumentation(handle, logger_tag_pop_count)
82
+ handle.finish
83
+ logger.pop_tags(logger_tag_pop_count) if logger.respond_to?(:pop_tags) && logger_tag_pop_count > 0
84
+ ActiveSupport::LogSubscriber.flush_all!
85
+ end
78
86
  end
79
87
  end
80
88
  end
@@ -27,8 +27,8 @@ module Rails
27
27
  end
28
28
 
29
29
  private
30
- def method_missing(*args, &block)
31
- instance.send(*args, &block)
30
+ def method_missing(...)
31
+ instance.send(...)
32
32
  end
33
33
  end
34
34
  end
data/lib/rails/railtie.rb CHANGED
@@ -221,14 +221,13 @@ module Rails
221
221
 
222
222
  # If the class method does not have a method, then send the method call
223
223
  # to the Railtie instance.
224
- def method_missing(name, *args, &block)
224
+ def method_missing(name, ...)
225
225
  if !abstract_railtie? && instance.respond_to?(name)
226
- instance.public_send(name, *args, &block)
226
+ instance.public_send(name, ...)
227
227
  else
228
228
  super
229
229
  end
230
230
  end
231
- ruby2_keywords(:method_missing)
232
231
 
233
232
  # receives an instance variable identifier, set the variable value if is
234
233
  # blank and append given block to value, which will be used later in
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  namespace :app do
4
- desc "Update configs and some other initially generated files (or use just update:configs or update:bin)"
5
- task update: [ "update:configs", "update:bin", "update:active_storage", "update:upgrade_guide_info" ]
6
-
7
4
  desc "Apply the template supplied by LOCATION=(/path/to/template) or URL"
8
5
  task template: :environment do
9
6
  template = ENV["LOCATION"]
@@ -34,27 +31,4 @@ namespace :app do
34
31
  end
35
32
  end
36
33
  end
37
-
38
- namespace :update do
39
- require "rails/app_updater"
40
-
41
- # desc "Update config files from your current rails install"
42
- task :configs do
43
- Rails::AppUpdater.invoke_from_app_generator :create_boot_file
44
- Rails::AppUpdater.invoke_from_app_generator :update_config_files
45
- end
46
-
47
- # desc "Add new executables to the application bin/ directory"
48
- task :bin do
49
- Rails::AppUpdater.invoke_from_app_generator :update_bin_files
50
- end
51
-
52
- task :active_storage do
53
- Rails::AppUpdater.invoke_from_app_generator :update_active_storage
54
- end
55
-
56
- task :upgrade_guide_info do
57
- Rails::AppUpdater.invoke_from_app_generator :display_upgrade_guide_info
58
- end
59
- end
60
34
  end
@@ -7,7 +7,7 @@ namespace :tmp do
7
7
  tmp_dirs = [ "tmp/cache",
8
8
  "tmp/sockets",
9
9
  "tmp/pids",
10
- "tmp/cache/assets" ]
10
+ ]
11
11
 
12
12
  tmp_dirs.each { |d| directory d }
13
13
 
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en">
2
+ <html>
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <title><%= @page_title %></title>
@@ -61,14 +61,14 @@
61
61
  <body>
62
62
  <header>
63
63
  <dl>
64
- <% if @email.respond_to?(:smtp_envelope_from) && Array(@email.from) != Array(@email.smtp_envelope_from) %>
64
+ <% if Array(@email.from) != Array(@email.smtp_envelope_from) %>
65
65
  <dt>SMTP-From:</dt>
66
66
  <dd id="smtp_from"><%= @email.smtp_envelope_from %></dd>
67
67
  <% end %>
68
68
 
69
- <% if @email.respond_to?(:smtp_envelope_to) && @email.to != @email.smtp_envelope_to %>
69
+ <% if Set[*@email.to, *@email.cc, *@email.bcc] != Set[*@email.smtp_envelope_to] %>
70
70
  <dt>SMTP-To:</dt>
71
- <dd id="smtp_to"><%= @email.smtp_envelope_to %></dd>
71
+ <dd id="smtp_to"><%= @email.smtp_envelope_to.join(", ") %></dd>
72
72
  <% end %>
73
73
 
74
74
  <dt>From:</dt>
@@ -93,17 +93,21 @@
93
93
  <% end %>
94
94
 
95
95
  <dt>Date:</dt>
96
- <dd id="date"><%= Time.current.rfc2822 %></dd>
96
+ <dd id="date"><%= @email.header['date'] || Time.current.rfc2822 %></dd>
97
97
 
98
98
  <dt>Subject:</dt>
99
99
  <dd><strong id="subject"><%= @email.subject %></strong></dd>
100
100
 
101
- <% unless @email.attachments.nil? || @email.attachments.empty? %>
101
+ <% if @attachments.any? || @inline_attachments.any? %>
102
102
  <dt>Attachments:</dt>
103
103
  <dd>
104
- <% @email.attachments.each do |a| %>
105
- <% filename = a.respond_to?(:original_filename) ? a.original_filename : a.filename %>
106
- <%= link_to filename, "data:application/octet-stream;charset=utf-8;base64,#{Base64.encode64(a.body.to_s)}", download: filename %>
104
+ <% @attachments.each do |filename, attachment| %>
105
+ <%= link_to filename, attachment_url(attachment), download: filename %>
106
+ <% end %>
107
+
108
+ <% if @inline_attachments.any? %>
109
+ (Inline: <% @inline_attachments.each do |filename, attachment| %>
110
+ <%= link_to filename, attachment_url(attachment), download: filename %><% end %>)
107
111
  <% end %>
108
112
  </dd>
109
113
  <% end %>
@@ -1,11 +1,12 @@
1
- <% ruby_on_rails_logo_favicon_data_uri = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIwcHgiIGhlaWdodD0iMzIwcHgiIHZpZXdCb3g9IjAgMCAzMjAgMzIwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPHRpdGxlPkljb248L3RpdGxlPgogICAgPGcgaWQ9Ikljb24iIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJSdWJ5LU9uLVJhaWxzLUxvZ28iIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUuMDAwMDAwLCAyMC4wMDAwMDApIiBmaWxsPSIjRDgxRTAwIj4KICAgICAgICAgICAgPHBhdGggZD0iTTIxLjkzMzA3MDYsMjg1IEwxNjguMTc1NDI2LDI4NSBDMTQ3Ljk0MDg1OCwxNTAuNjkxNzA2IDE5Ni44ODIzODMsNjYuMzE0MjkwMiAzMTUsMzEuODY3NzUzNiBDMzE1LDIxLjc4NTEyODQgMzE1LDMxLjg2Nzc1MzYgMzE1LDIxLjc4NTEyODQgQzE2MS4yNTI4MywyNC45MTE2Mjc4IDYzLjU2Mzg1MzMsMTEyLjY0OTkxOCAyMS45MzMwNzA2LDI4NSBaIiBpZD0iUGF0aCIvPgogICAgICAgICAgICA8cG9seWdvbiBpZD0iUGF0aCIgcG9pbnRzPSI0MC40MDgyNjQzIDE4NS45MTU3MSAxMi43MzI2NDk0IDE3NC40MDE2NjMgLTEuNDIxMDg1NDdlLTE0IDIwNS40NDI3MSAyOS41NzExOTY2IDIxNi42NDcxMTUiLz4KICAgICAgICAgICAgPHBvbHlnb24gaWQ9IlBhdGgiIHBvaW50cz0iMTgwLjQ3MzEwMiAyNjguMDczNjQzIDIwNC45MzYwMTYgMjc2LjQxMDk2NiAyMDQuOTM2MDE2IDI1NC41MDg2NzMgMTgwLjQ4OTY0NCAyNDQuMzM4MTA3Ii8+CiAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJQYXRoIiBwb2ludHM9IjEwMC41ODk1MTkgOTcuMjI4NzYwNiA3Ni42ODQwMTU2IDc5LjE2ODcwMjEgNTUuMjQ0MDc5MSAxMDAuMTgzMTA1IDgxLjUxNDMyMzkgMTE3LjQzMzcyNSIvPgogICAgICAgICAgICA8cG9seWdvbiBpZD0iUGF0aCIgcG9pbnRzPSIxODQuNTc1Njc5IDE4NC44OTYyOTUgMjA3Ljk1MjAzIDIwMC4yNDY2MSAyMTEuNzI3NzI5IDE4MS4yMDUyNjYgMTg5Ljg2MzY1MyAxNjQuNjg3NDYiLz4KICAgICAgICAgICAgPHBvbHlnb24gaWQ9IlBhdGgiIHBvaW50cz0iMjYxLjczNDAxIDY1Ljg5NTk0NDYgMjY5LjM1NDIzNCA4Mi4zMjk1NCAyODUuMzE4MjU2IDcyLjcwNDg1OTYgMjc4LjMxMDEyOSA1Ni45ODI5ODk1Ii8+CiAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJQYXRoIiBwb2ludHM9IjI2MS45MTM3IDE2LjE4NDU0NzMgMjU1LjU5ODQ3OSA3LjEwNTQyNzM2ZS0xNSAyMzIuNzk2MDIgMy40ODg5NjMyMyAyNDAuNDYzODczIDIwLjAyNTI3MjUiLz4KICAgICAgICAgICAgPHBvbHlnb24gaWQ9IlBhdGgiIHBvaW50cz0iMjExLjkzNDExOSAxMTEuNTgwNjc1IDIyNi43MjI1NDcgMTI3Ljc5MjYwMSAyMzguMDIzOTI1IDExMy45MDM3MTUgMjIzLjQ2ODM3NSA5Ni41NDY4Njg1Ii8+CiAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJQYXRoIiBwb2ludHM9IjE3OS42ODY4NTggMzguNDk1MjIxOCAxNjQuNjQxOTMxIDIwLjAyNTI3MjUgMTM5Ljg0NzYyIDMyLjU1NTI5OTIgMTU2LjYwMTMyNCA1MC45MjE2NzUzIi8+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4=" %>
2
1
  <!DOCTYPE html>
3
2
  <html>
4
3
  <head>
5
4
  <title>Ruby on Rails <%= Rails.version %></title>
6
5
  <meta charset="utf-8">
7
6
  <meta name="viewport" content="width=device-width">
8
- <link rel="icon" href="<%= ruby_on_rails_logo_favicon_data_uri %>" />
7
+
8
+ <link rel="icon" href="/icon.png" type="image/png">
9
+ <link rel="apple-touch-icon" href="/icon.png" sizes="512x512">
9
10
 
10
11
  <style type="text/css">
11
12
  * {
@@ -84,6 +85,7 @@
84
85
 
85
86
  <ul>
86
87
  <li><strong>Rails version:</strong> <%= Rails.version %></li>
88
+ <li><strong>Rack version:</strong> <%= Rack.release %></li>
87
89
  <li><strong>Ruby version:</strong> <%= RUBY_DESCRIPTION %></li>
88
90
  </ul>
89
91
  </body>
@@ -7,19 +7,17 @@
7
7
  abort("Abort testing: Your Rails environment is running in production mode!") if Rails.env.production?
8
8
 
9
9
  require "active_support/test_case"
10
- require "action_controller"
11
- require "action_controller/test_case"
12
- require "action_dispatch/testing/integration"
13
10
  require "rails/generators/test_case"
14
-
15
11
  require "active_support/testing/autorun"
16
12
 
17
13
  require "rails/testing/maintain_test_schema"
18
14
 
19
15
  if defined?(ActiveRecord::Base)
16
+ require "active_record/testing/query_assertions"
20
17
  ActiveSupport.on_load(:active_support_test_case) do
21
18
  include ActiveRecord::TestDatabases
22
19
  include ActiveRecord::TestFixtures
20
+ include ActiveRecord::Assertions::QueryAssertions
23
21
 
24
22
  self.fixture_paths << "#{Rails.root}/test/fixtures/"
25
23
  self.file_fixture_path = "#{Rails.root}/test/fixtures/files"
@@ -8,6 +8,13 @@ module Rails
8
8
  class_attribute :app_root
9
9
  class_attribute :executable, default: "bin/rails test"
10
10
 
11
+ def prerecord(test_class, test_name)
12
+ super
13
+ if options[:verbose]
14
+ io.print "%s#%s = " % [test_class.name, test_name]
15
+ end
16
+ end
17
+
11
18
  def record(result)
12
19
  super
13
20
 
@@ -69,8 +76,7 @@ module Rails
69
76
  end
70
77
 
71
78
  def format_line(result)
72
- klass = result.respond_to?(:klass) ? result.klass : result.class
73
- "%s#%s = %.2f s = %s" % [klass, result.name, result.time, result.result_code]
79
+ "%.2f s = %s" % [result.time, result.result_code]
74
80
  end
75
81
 
76
82
  def format_rerun_snippet(result)
@@ -9,6 +9,15 @@ require "rails/test_unit/test_parser"
9
9
 
10
10
  module Rails
11
11
  module TestUnit
12
+ class InvalidTestError < StandardError
13
+ def initialize(path, suggestion)
14
+ super(<<~MESSAGE.squish)
15
+ Could not load test file: #{path}.
16
+ #{suggestion}
17
+ MESSAGE
18
+ end
19
+ end
20
+
12
21
  class Runner
13
22
  TEST_FOLDERS = [:models, :helpers, :channels, :controllers, :mailers, :integration, :jobs, :mailboxes]
14
23
  PATH_ARGUMENT_PATTERN = %r"^(?!/.+/$)[.\w]*[/\\]"
@@ -48,7 +57,22 @@ module Rails
48
57
  def load_tests(argv)
49
58
  patterns = extract_filters(argv)
50
59
  tests = list_tests(patterns)
51
- tests.to_a.each { |path| require File.expand_path(path) }
60
+ tests.to_a.each do |path|
61
+ abs_path = File.expand_path(path)
62
+ require abs_path
63
+ rescue LoadError => exception
64
+ if exception.path == abs_path
65
+ all_tests = list_tests([default_test_glob])
66
+ corrections = DidYouMean::SpellChecker.new(dictionary: all_tests).correct(path)
67
+
68
+ if corrections.empty?
69
+ raise exception
70
+ end
71
+ raise InvalidTestError.new(path, DidYouMean::Formatter.message_for(corrections))
72
+ else
73
+ raise
74
+ end
75
+ end
52
76
  end
53
77
 
54
78
  def compose_filter(runnable, filter)
@@ -87,7 +111,7 @@ module Rails
87
111
  end
88
112
 
89
113
  def default_test_exclude_glob
90
- ENV["DEFAULT_TEST_EXCLUDE"] || "test/{system,dummy}/**/*_test.rb"
114
+ ENV["DEFAULT_TEST_EXCLUDE"] || "test/{system,dummy,fixtures}/**/*_test.rb"
91
115
  end
92
116
 
93
117
  def regexp_filter?(arg)
@@ -1,5 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
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 parser using ripper.
8
+ end
9
+
10
+ if defined?(Prism)
11
+ module Rails
12
+ module TestUnit
13
+ # Parse a test file to extract the line ranges of all tests in both
14
+ # method-style (def test_foo) and declarative-style (test "foo" do)
15
+ module TestParser
16
+ # Helper to translate a method object into the path and line range where
17
+ # the method was defined.
18
+ def self.definition_for(method)
19
+ filepath, start_line = method.source_location
20
+ queue = [Prism.parse_file(filepath).value]
21
+
22
+ while (node = queue.shift)
23
+ case node.type
24
+ when :def_node
25
+ if node.location.start_line == start_line
26
+ return [filepath, start_line..node.location.end_line]
27
+ end
28
+ when :call_node
29
+ if node.location.start_line == start_line
30
+ return [filepath, start_line..node.location.end_line]
31
+ end
32
+ end
33
+
34
+ queue.concat(node.compact_child_nodes)
35
+ end
36
+
37
+ nil
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ # If we have Prism, then we don't need to define the fallback parser using
44
+ # ripper.
45
+ return
46
+ end
47
+
3
48
  require "ripper"
4
49
 
5
50
  module Rails
data/lib/rails.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rails/ruby_version_check"
4
-
5
3
  require "pathname"
6
4
 
7
5
  require "active_support"
@@ -24,17 +22,21 @@ silence_warnings do
24
22
  Encoding.default_internal = Encoding::UTF_8
25
23
  end
26
24
 
27
- # :include: railties/README.rdoc
25
+ # :include: ../README.rdoc
28
26
  module Rails
29
27
  extend ActiveSupport::Autoload
30
28
  extend ActiveSupport::Benchmarkable
31
29
 
32
- autoload :HealthController
33
30
  autoload :Info
34
31
  autoload :InfoController
35
32
  autoload :MailersController
36
33
  autoload :WelcomeController
37
34
 
35
+ eager_autoload do
36
+ autoload :HealthController
37
+ autoload :PwaController
38
+ end
39
+
38
40
  class << self
39
41
  @application = @app_class = nil
40
42
 
@@ -69,6 +71,7 @@ module Rails
69
71
  # Rails.env # => "development"
70
72
  # Rails.env.development? # => true
71
73
  # Rails.env.production? # => false
74
+ # Rails.env.local? # => true true for "development" and "test", false for anything else
72
75
  def env
73
76
  @_env ||= ActiveSupport::EnvironmentInquirer.new(ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || "development")
74
77
  end