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
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rails/generators/app_base"
4
+ require "rails/generators/rails/devcontainer/devcontainer_generator"
4
5
 
5
6
  module Rails
6
7
  module ActionMethods # :nodoc:
@@ -15,14 +16,14 @@ module Rails
15
16
  %w(template copy_file directory empty_directory inside
16
17
  empty_directory_with_keep_file create_file chmod shebang).each do |method|
17
18
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
18
- def #{method}(*args, &block)
19
- @generator.send(:#{method}, *args, &block)
19
+ def #{method}(...)
20
+ @generator.send(:#{method}, ...)
20
21
  end
21
22
  RUBY
22
23
  end
23
24
 
24
- def method_missing(meth, *args, &block)
25
- @generator.send(meth, *args, &block)
25
+ def method_missing(...)
26
+ @generator.send(...)
26
27
  end
27
28
  end
28
29
 
@@ -54,6 +55,10 @@ module Rails
54
55
  template "ruby-version", ".ruby-version"
55
56
  end
56
57
 
58
+ def node_version
59
+ template "node-version", ".node-version"
60
+ end
61
+
57
62
  def gemfile
58
63
  template "Gemfile"
59
64
  end
@@ -70,12 +75,27 @@ module Rails
70
75
  template "gitattributes", ".gitattributes"
71
76
  end
72
77
 
78
+ def dockerfiles
79
+ template "Dockerfile"
80
+ template "dockerignore", ".dockerignore"
81
+
82
+ template "docker-entrypoint", "bin/docker-entrypoint"
83
+ chmod "bin/docker-entrypoint", 0755 & ~File.umask, verbose: false
84
+ end
85
+
86
+ def cifiles
87
+ empty_directory ".github/workflows"
88
+ template "github/ci.yml", ".github/workflows/ci.yml"
89
+ template "github/dependabot.yml", ".github/dependabot.yml"
90
+ end
91
+
92
+ def rubocop
93
+ template "rubocop.yml", ".rubocop.yml"
94
+ end
95
+
73
96
  def version_control
74
97
  if !options[:skip_git] && !options[:pretend]
75
- run "git init", capture: options[:quiet], abort_on_failure: false
76
- if user_default_branch.strip.empty?
77
- `git symbolic-ref HEAD refs/heads/main`
78
- end
98
+ run git_init_command, capture: options[:quiet], abort_on_failure: false
79
99
  end
80
100
  end
81
101
 
@@ -89,7 +109,8 @@ module Rails
89
109
  end
90
110
 
91
111
  def bin
92
- directory "bin" do |content|
112
+ exclude_pattern = Regexp.union([(/rubocop/ if skip_rubocop?), (/brakeman/ if skip_brakeman?)].compact)
113
+ directory "bin", { exclude_pattern: exclude_pattern } do |content|
93
114
  "#{shebang}\n" + content
94
115
  end
95
116
  chmod "bin", 0755 & ~File.umask, verbose: false
@@ -103,16 +124,16 @@ module Rails
103
124
  empty_directory "config"
104
125
 
105
126
  inside "config" do
106
- template "routes.rb" unless options[:updating]
127
+ template "routes.rb" unless options[:update]
107
128
  template "application.rb"
108
129
  template "environment.rb"
109
- template "cable.yml" unless options[:updating] || options[:skip_action_cable]
110
- template "puma.rb" unless options[:updating]
111
- template "storage.yml" unless options[:updating] || skip_active_storage?
130
+ template "cable.yml" unless options[:update] || options[:skip_action_cable]
131
+ template "puma.rb"
132
+ template "storage.yml" unless options[:update] || skip_active_storage?
112
133
 
113
134
  directory "environments"
114
135
  directory "initializers"
115
- directory "locales" unless options[:updating]
136
+ directory "locales" unless options[:update]
116
137
  end
117
138
  end
118
139
 
@@ -163,10 +184,6 @@ module Rails
163
184
  remove_file "config/initializers/permissions_policy.rb"
164
185
  end
165
186
  end
166
-
167
- if !skip_sprockets?
168
- insert_into_file "config/application.rb", %(require "sprockets/railtie"), after: /require\(["']rails\/all["']\)\n/
169
- end
170
187
  end
171
188
 
172
189
  def master_key
@@ -182,7 +199,15 @@ module Rails
182
199
  return if options[:pretend] || options[:dummy_app]
183
200
 
184
201
  require "rails/generators/rails/credentials/credentials_generator"
185
- Rails::Generators::CredentialsGenerator.new([], quiet: options[:quiet]).add_credentials_file_silently
202
+ Rails::Generators::CredentialsGenerator.new([], quiet: true).add_credentials_file
203
+ end
204
+
205
+ def credentials_diff_enroll
206
+ return if options[:skip_decrypted_diffs] || options[:dummy_app] || options[:pretend]
207
+
208
+ @generator.shell.mute do
209
+ rails_command "credentials:diff --enroll", inline: true, shell: @generator.shell
210
+ end
186
211
  end
187
212
 
188
213
  def database_yml
@@ -193,14 +218,6 @@ module Rails
193
218
  directory "db"
194
219
  end
195
220
 
196
- def db_when_updating
197
- path = File.expand_path("db/schema.rb", destination_root)
198
-
199
- if File.exist?(path)
200
- gsub_file("db/schema.rb", /ActiveRecord::Schema\.define/, "ActiveRecord::Schema[6.1].define")
201
- end
202
- end
203
-
204
221
  def lib
205
222
  empty_directory "lib"
206
223
  empty_directory_with_keep_file "lib/tasks"
@@ -241,8 +258,6 @@ module Rails
241
258
  def tmp
242
259
  empty_directory_with_keep_file "tmp"
243
260
  empty_directory_with_keep_file "tmp/pids"
244
- empty_directory "tmp/cache"
245
- empty_directory "tmp/cache/assets"
246
261
  end
247
262
 
248
263
  def vendor
@@ -250,13 +265,22 @@ module Rails
250
265
  end
251
266
 
252
267
  def config_target_version
253
- defined?(@config_target_version) ? @config_target_version : Rails::VERSION::STRING.to_f
268
+ @config_target_version || Rails::VERSION::STRING.to_f
254
269
  end
255
270
 
256
- private
257
- def user_default_branch
258
- @user_default_branch ||= `git config init.defaultbranch`
259
- end
271
+ def devcontainer
272
+ devcontainer_options = {
273
+ database: options[:database],
274
+ redis: !(options[:skip_action_cable] && options[:skip_active_job]),
275
+ system_test: depends_on_system_test?,
276
+ active_storage: !options[:skip_active_storage],
277
+ dev: options[:dev],
278
+ node: using_node?,
279
+ app_name: app_name
280
+ }
281
+
282
+ Rails::Generators::DevcontainerGenerator.new([], devcontainer_options).invoke_all
283
+ end
260
284
  end
261
285
 
262
286
  module Generators
@@ -273,42 +297,55 @@ module Rails
273
297
  class_option :version, type: :boolean, aliases: "-v", group: :rails, desc: "Show Rails version number and quit"
274
298
  class_option :api, type: :boolean, desc: "Preconfigure smaller stack for API only apps"
275
299
  class_option :minimal, type: :boolean, desc: "Preconfigure a minimal rails app"
276
- class_option :javascript, type: :string, aliases: "-j", default: "importmap", desc: "Choose JavaScript approach [options: importmap (default), webpack, esbuild, rollup]"
277
- class_option :css, type: :string, aliases: "-c", desc: "Choose CSS processor [options: tailwind, bootstrap, bulma, postcss, sass] check https://github.com/rails/cssbundling-rails"
278
- class_option :skip_bundle, type: :boolean, aliases: "-B", default: false, desc: "Don't run bundle install"
300
+ class_option :javascript, type: :string, aliases: ["-j", "--js"], default: "importmap", enum: JAVASCRIPT_OPTIONS, desc: "Choose JavaScript approach"
301
+ class_option :css, type: :string, aliases: "-c", enum: CSS_OPTIONS, desc: "Choose CSS processor. Check https://github.com/rails/cssbundling-rails for more options"
302
+ class_option :skip_bundle, type: :boolean, aliases: "-B", default: nil, desc: "Don't run bundle install"
303
+ class_option :skip_decrypted_diffs, type: :boolean, default: nil, desc: "Don't configure git to show decrypted diffs of encrypted credentials"
304
+
305
+ OPTION_IMPLICATIONS = # :nodoc:
306
+ AppBase::OPTION_IMPLICATIONS.merge(
307
+ skip_git: [:skip_decrypted_diffs],
308
+ minimal: [
309
+ :skip_action_cable,
310
+ :skip_action_mailbox,
311
+ :skip_action_mailer,
312
+ :skip_action_text,
313
+ :skip_active_job,
314
+ :skip_active_storage,
315
+ :skip_bootsnap,
316
+ :skip_dev_gems,
317
+ :skip_hotwire,
318
+ :skip_javascript,
319
+ :skip_jbuilder,
320
+ :skip_system_test,
321
+ ],
322
+ api: [
323
+ :skip_asset_pipeline,
324
+ :skip_javascript,
325
+ ],
326
+ ) do |option, implications, more_implications|
327
+ implications + more_implications
328
+ end
279
329
 
280
- def initialize(*args)
281
- super
330
+ META_OPTIONS = [:minimal] # :nodoc:
282
331
 
283
- if !options[:skip_active_record] && !DATABASES.include?(options[:database])
284
- raise Error, "Invalid value for --database option. Supported preconfigurations are: #{DATABASES.join(", ")}."
285
- end
332
+ def self.apply_rails_template(template, destination) # :nodoc:
333
+ generator = new([destination], { template: template }, { destination_root: destination })
334
+ generator.set_default_accessors!
335
+ generator.apply_rails_template
336
+ generator.run_bundle
337
+ generator.run_after_bundle_callbacks
338
+ end
286
339
 
287
- # Force sprockets and JavaScript to be skipped when generating API only apps.
288
- # Can't modify options hash as it's frozen by default.
289
- if options[:api]
290
- self.options = options.merge(skip_asset_pipeline: true, skip_javascript: true).freeze
291
- end
340
+ def initialize(*args)
341
+ super
292
342
 
293
- if options[:minimal]
294
- self.options = options.merge(
295
- skip_action_cable: true,
296
- skip_action_mailer: true,
297
- skip_action_mailbox: true,
298
- skip_action_text: true,
299
- skip_active_job: true,
300
- skip_active_storage: true,
301
- skip_bootsnap: true,
302
- skip_dev_gems: true,
303
- skip_javascript: true,
304
- skip_jbuilder: true,
305
- skip_system_test: true,
306
- skip_hotwire: true).freeze
307
- end
343
+ imply_options(OPTION_IMPLICATIONS, meta_options: META_OPTIONS)
308
344
 
309
345
  @after_bundle_callbacks = []
310
346
  end
311
347
 
348
+ public_task :report_implied_options
312
349
  public_task :set_default_accessors!
313
350
  public_task :create_root
314
351
  public_task :target_rails_prerelease
@@ -316,6 +353,7 @@ module Rails
316
353
  def create_root_files
317
354
  build(:readme)
318
355
  build(:rakefile)
356
+ build(:node_version) if using_node?
319
357
  build(:ruby_version)
320
358
  build(:configru)
321
359
 
@@ -341,11 +379,6 @@ module Rails
341
379
  end
342
380
  remove_task :update_bin_files
343
381
 
344
- def update_db_schema
345
- build(:db_when_updating)
346
- end
347
- remove_task :update_db_schema
348
-
349
382
  def update_active_storage
350
383
  unless skip_active_storage?
351
384
  rails_command "active_storage:update", inline: true
@@ -353,6 +386,21 @@ module Rails
353
386
  end
354
387
  remove_task :update_active_storage
355
388
 
389
+ def create_dockerfiles
390
+ return if options[:skip_docker] || options[:dummy_app]
391
+ build(:dockerfiles)
392
+ end
393
+
394
+ def create_rubocop_file
395
+ return if skip_rubocop?
396
+ build(:rubocop)
397
+ end
398
+
399
+ def create_cifiles
400
+ return if skip_ci?
401
+ build(:cifiles)
402
+ end
403
+
356
404
  def create_config_files
357
405
  build(:config)
358
406
  end
@@ -368,13 +416,9 @@ module Rails
368
416
 
369
417
  def create_credentials
370
418
  build(:credentials)
419
+ build(:credentials_diff_enroll)
371
420
  end
372
421
 
373
- def display_upgrade_guide_info
374
- say "\nAfter this, check Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html for more details about upgrading your app."
375
- end
376
- remove_task :display_upgrade_guide_info
377
-
378
422
  def create_boot_file
379
423
  template "config/boot.rb"
380
424
  end
@@ -418,14 +462,18 @@ module Rails
418
462
  end
419
463
 
420
464
  def create_storage_files
421
- build(:storage) unless skip_active_storage?
465
+ build(:storage) unless skip_storage?
466
+ end
467
+
468
+ def create_devcontainer_files
469
+ return if skip_devcontainer? || options[:dummy_app]
470
+ build(:devcontainer)
422
471
  end
423
472
 
424
473
  def delete_app_assets_if_api_option
425
474
  if options[:api]
426
475
  remove_dir "app/assets"
427
476
  remove_dir "lib/assets"
428
- remove_dir "tmp/cache/assets"
429
477
  end
430
478
  end
431
479
 
@@ -438,7 +486,7 @@ module Rails
438
486
 
439
487
  def delete_app_views_if_api_option
440
488
  if options[:api]
441
- if skip_action_mailer?
489
+ if options[:skip_action_mailer]
442
490
  remove_dir "app/views"
443
491
  else
444
492
  remove_file "app/views/layouts/application.html.erb"
@@ -449,11 +497,11 @@ module Rails
449
497
  def delete_public_files_if_api_option
450
498
  if options[:api]
451
499
  remove_file "public/404.html"
500
+ remove_file "public/406-unsupported-browser.html"
452
501
  remove_file "public/422.html"
453
502
  remove_file "public/500.html"
454
- remove_file "public/apple-touch-icon-precomposed.png"
455
- remove_file "public/apple-touch-icon.png"
456
- remove_file "public/favicon.ico"
503
+ remove_file "public/icon.png"
504
+ remove_file "public/icon.svg"
457
505
  end
458
506
  end
459
507
 
@@ -483,7 +531,7 @@ module Rails
483
531
  end
484
532
 
485
533
  def delete_action_mailer_files_skipping_action_mailer
486
- if skip_action_mailer?
534
+ if options[:skip_action_mailer]
487
535
  remove_file "app/views/layouts/mailer.html.erb"
488
536
  remove_file "app/views/layouts/mailer.text.erb"
489
537
  remove_dir "app/mailers"
@@ -514,7 +562,7 @@ module Rails
514
562
 
515
563
  def delete_new_framework_defaults
516
564
  unless options[:update]
517
- remove_file "config/initializers/new_framework_defaults_7_0.rb"
565
+ remove_file "config/initializers/new_framework_defaults_#{Rails::VERSION::MAJOR}_#{Rails::VERSION::MINOR}.rb"
518
566
  end
519
567
  end
520
568
 
@@ -522,7 +570,9 @@ module Rails
522
570
  build(:leftovers)
523
571
  end
524
572
 
525
- public_task :apply_rails_template, :run_bundle
573
+ public_task :apply_rails_template
574
+ public_task :run_bundle
575
+ public_task :add_bundler_platforms
526
576
  public_task :generate_bundler_binstub
527
577
  public_task :run_javascript
528
578
  public_task :run_hotwire
@@ -623,7 +673,7 @@ module Rails
623
673
  end
624
674
 
625
675
  def read_rc_file(railsrc)
626
- extra_args = File.readlines(railsrc).flat_map(&:split)
676
+ extra_args = File.readlines(railsrc).flat_map.each { |line| line.split("#", 2).first.split }
627
677
  puts "Using #{extra_args.join(" ")} from #{railsrc}"
628
678
  extra_args
629
679
  end
@@ -0,0 +1,110 @@
1
+ # syntax = docker/dockerfile:1
2
+
3
+ # This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand:
4
+ # docker build -t my-app .
5
+ # docker run -d -p 80:80 -p 443:443 --name my-app -e RAILS_MASTER_KEY=<value from config/master.key> my-app
6
+
7
+ # Make sure RUBY_VERSION matches the Ruby version in .ruby-version
8
+ ARG RUBY_VERSION=<%= gem_ruby_version %>
9
+ FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base
10
+
11
+ # Rails app lives here
12
+ WORKDIR /rails
13
+
14
+ # Install base packages
15
+ RUN apt-get update -qq && \
16
+ apt-get install --no-install-recommends -y <%= dockerfile_base_packages.join(" ") %> && \
17
+ rm -rf /var/lib/apt/lists /var/cache/apt/archives
18
+
19
+ # Set production environment
20
+ ENV RAILS_ENV="production" \
21
+ BUNDLE_DEPLOYMENT="1" \
22
+ BUNDLE_PATH="/usr/local/bundle" \
23
+ BUNDLE_WITHOUT="development"
24
+
25
+ # Throw-away build stage to reduce size of final image
26
+ FROM base AS build
27
+
28
+ # Install packages needed to build gems<%= using_node? ? " and node modules" : "" %>
29
+ RUN apt-get update -qq && \
30
+ apt-get install --no-install-recommends -y <%= dockerfile_build_packages.join(" ") %> && \
31
+ rm -rf /var/lib/apt/lists /var/cache/apt/archives
32
+
33
+ <% if using_node? -%>
34
+ # Install JavaScript dependencies
35
+ ARG NODE_VERSION=<%= node_version %>
36
+ ARG YARN_VERSION=<%= dockerfile_yarn_version %>
37
+ ENV PATH=/usr/local/node/bin:$PATH
38
+ RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
39
+ /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
40
+ npm install -g yarn@$YARN_VERSION && \
41
+ rm -rf /tmp/node-build-master
42
+
43
+ <% end -%>
44
+ <% if using_bun? -%>
45
+ ENV BUN_INSTALL=/usr/local/bun
46
+ ENV PATH=/usr/local/bun/bin:$PATH
47
+ ARG BUN_VERSION=<%= dockerfile_bun_version %>
48
+ RUN curl -fsSL https://bun.sh/install | bash -s -- "bun-v${BUN_VERSION}"
49
+
50
+ <% end -%>
51
+ # Install application gems
52
+ COPY Gemfile Gemfile.lock ./
53
+ RUN bundle install && \
54
+ rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git<% if depend_on_bootsnap? -%> && \
55
+ bundle exec bootsnap precompile --gemfile<% end %>
56
+
57
+ <% if using_node? -%>
58
+ # Install node modules
59
+ COPY package.json yarn.lock ./
60
+ RUN yarn install --frozen-lockfile
61
+
62
+ <% end -%>
63
+ <% if using_bun? -%>
64
+ # Install node modules
65
+ COPY package.json bun.lockb ./
66
+ RUN bun install --frozen-lockfile
67
+
68
+ <% end -%>
69
+ # Copy application code
70
+ COPY . .
71
+
72
+ <% if depend_on_bootsnap? -%>
73
+ # Precompile bootsnap code for faster boot times
74
+ RUN bundle exec bootsnap precompile app/ lib/
75
+
76
+ <% end -%>
77
+ <% unless dockerfile_binfile_fixups.empty? -%>
78
+ # Adjust binfiles to be executable on Linux
79
+ <%= "RUN " + dockerfile_binfile_fixups.join(" && \\\n ") %>
80
+
81
+ <% end -%>
82
+ <% unless options.api? || skip_asset_pipeline? -%>
83
+ # Precompiling assets for production without requiring secret RAILS_MASTER_KEY
84
+ RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
85
+
86
+ <% end -%>
87
+
88
+ <% if using_node? -%>
89
+ RUN rm -rf node_modules
90
+ <% end %>
91
+
92
+ # Final stage for app image
93
+ FROM base
94
+
95
+ # Copy built artifacts: gems, application
96
+ COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
97
+ COPY --from=build /rails /rails
98
+
99
+ # Run and own only the runtime files as a non-root user for security
100
+ RUN groupadd --system --gid 1000 rails && \
101
+ useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
102
+ chown -R rails:rails <%= dockerfile_chown_directories.join(" ") %>
103
+ USER 1000:1000
104
+
105
+ # Entrypoint prepares the database.
106
+ ENTRYPOINT ["/rails/bin/docker-entrypoint"]
107
+
108
+ # Start the server by default, this can be overwritten at runtime
109
+ EXPOSE 3000
110
+ CMD ["./bin/rails", "server"]
@@ -1,9 +1,6 @@
1
1
  source "https://rubygems.org"
2
- git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3
2
 
4
- ruby <%= "\"#{RUBY_VERSION}\"" -%>
5
-
6
- <% gemfile_entries.each do |gemfile_entry| %>
3
+ <% gemfile_entries.each do |gemfile_entry| -%>
7
4
  <%= gemfile_entry %>
8
5
  <% end -%>
9
6
  <% unless options.minimal? -%>
@@ -16,17 +13,12 @@ ruby <%= "\"#{RUBY_VERSION}\"" -%>
16
13
  <% end -%>
17
14
 
18
15
  # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
19
- gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]
16
+ gem "tzinfo-data", platforms: %i[ <%= bundler_windows_platforms %> jruby ]
20
17
  <% if depend_on_bootsnap? -%>
21
18
 
22
19
  # Reduces boot times through caching; required in config/boot.rb
23
20
  gem "bootsnap", require: false
24
21
  <% end -%>
25
- <% unless skip_sprockets? || options.minimal? -%>
26
-
27
- # Use Sass to process CSS
28
- # gem "sassc-rails"
29
- <% end -%>
30
22
  <% unless skip_active_storage? -%>
31
23
 
32
24
  # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
@@ -34,37 +26,43 @@ gem "bootsnap", require: false
34
26
  <% end -%>
35
27
  <%- if options.api? -%>
36
28
 
37
- # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
29
+ # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin Ajax possible
38
30
  # gem "rack-cors"
39
31
  <%- end -%>
40
32
  <% if RUBY_ENGINE == "ruby" -%>
41
33
 
42
34
  group :development, :test do
43
35
  # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
44
- gem "debug", platforms: %i[ mri mingw x64_mingw ]
36
+ gem "debug", platforms: %i[ mri <%= bundler_windows_platforms %> ], require: "debug/prelude"
37
+ <%- unless options.skip_brakeman? -%>
38
+
39
+ # Static analysis for security vulnerabilities [https://brakemanscanner.org/]
40
+ gem "brakeman", require: false
41
+ <%- end -%>
42
+ <%- unless options.skip_rubocop? -%>
43
+
44
+ # Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/]
45
+ gem "rubocop-rails-omakase", require: false
46
+ <%- end -%>
45
47
  end
46
48
  <% end -%>
47
49
 
48
- group :development do
49
50
  <%- unless options.api? || options.skip_dev_gems? -%>
51
+ group :development do
50
52
  # Use console on exceptions pages [https://github.com/rails/web-console]
51
53
  gem "web-console"
54
+ <%- if RUBY_VERSION < "3.2" -%>
52
55
 
53
- # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
54
- # gem "rack-mini-profiler"
55
-
56
+ # Highlight the fine-grained location where an error occurred [https://github.com/ruby/error_highlight]
57
+ gem "error_highlight", ">= 0.4.0", platforms: [:ruby]
56
58
  <%- end -%>
57
- # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
58
- # gem "spring"
59
59
  end
60
+ <%- end -%>
60
61
 
61
62
  <%- if depends_on_system_test? -%>
62
63
  group :test do
63
64
  # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
64
65
  gem "capybara"
65
66
  gem "selenium-webdriver"
66
- <%- if RUBY_VERSION < "3.0" -%>
67
- gem "webdrivers"
68
- <% end %>
69
67
  end
70
68
  <%- end -%>
@@ -1,2 +1,6 @@
1
1
  class ApplicationController < ActionController::<%= options.api? ? "API" : "Base" %>
2
+ <%- unless options.api? -%>
3
+ # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
4
+ allow_browser versions: :modern
5
+ <% end -%>
2
6
  end
@@ -1,11 +1,18 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <title><%= camelized %></title>
4
+ <title><%%= content_for(:title) || "<%= app_name.titleize %>" %></title>
5
5
  <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <meta name="apple-mobile-web-app-capable" content="yes">
6
7
  <%%= csrf_meta_tags %>
7
8
  <%%= csp_meta_tag %>
8
9
 
10
+ <%%= yield :head %>
11
+
12
+ <link rel="manifest" href="/manifest.json">
13
+ <link rel="icon" href="/icon.png" type="image/png">
14
+ <link rel="icon" href="/icon.svg" type="image/svg+xml">
15
+ <link rel="apple-touch-icon" href="/icon.png">
9
16
  <%- if options[:skip_hotwire] || options[:skip_javascript] -%>
10
17
  <%%= stylesheet_link_tag "application" %>
11
18
  <%- else -%>
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
5
  <style>
6
6
  /* Email styles need to be inline */
7
7
  </style>
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "<%= camelized %>",
3
+ "icons": [
4
+ {
5
+ "src": "/icon.png",
6
+ "type": "image/png",
7
+ "sizes": "512x512"
8
+ },
9
+ {
10
+ "src": "/icon.png",
11
+ "type": "image/png",
12
+ "sizes": "512x512",
13
+ "purpose": "maskable"
14
+ }
15
+ ],
16
+ "start_url": "/",
17
+ "display": "standalone",
18
+ "scope": "/",
19
+ "description": "<%= camelized %>.",
20
+ "theme_color": "red",
21
+ "background_color": "red"
22
+ }
@@ -0,0 +1,26 @@
1
+ // Add a service worker for processing Web Push notifications:
2
+ //
3
+ // self.addEventListener("push", async (event) => {
4
+ // const { title, options } = await event.data.json()
5
+ // event.waitUntil(self.registration.showNotification(title, options))
6
+ // })
7
+ //
8
+ // self.addEventListener("notificationclick", function(event) {
9
+ // event.notification.close()
10
+ // event.waitUntil(
11
+ // clients.matchAll({ type: "window" }).then((clientList) => {
12
+ // for (let i = 0; i < clientList.length; i++) {
13
+ // let client = clientList[i]
14
+ // let clientPath = (new URL(client.url)).pathname
15
+ //
16
+ // if (clientPath == event.notification.data.path && "focus" in client) {
17
+ // return client.focus()
18
+ // }
19
+ // }
20
+ //
21
+ // if (clients.openWindow) {
22
+ // return clients.openWindow(event.notification.data.path)
23
+ // }
24
+ // })
25
+ // )
26
+ // })