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
@@ -28,14 +28,14 @@ module Rails
28
28
 
29
29
  empty_directory_with_keep_file "app/models/concerns"
30
30
  empty_directory_with_keep_file "app/controllers/concerns"
31
- remove_dir "app/mailers" if skip_action_mailer?
31
+ remove_dir "app/mailers" if options[:skip_action_mailer]
32
32
  remove_dir "app/jobs" if options[:skip_active_job]
33
33
  elsif full?
34
34
  empty_directory_with_keep_file "app/models"
35
35
  empty_directory_with_keep_file "app/controllers"
36
36
  empty_directory_with_keep_file "app/models/concerns"
37
37
  empty_directory_with_keep_file "app/controllers/concerns"
38
- empty_directory_with_keep_file "app/mailers" unless skip_action_mailer?
38
+ empty_directory_with_keep_file "app/mailers" unless options[:skip_action_mailer]
39
39
  empty_directory_with_keep_file "app/jobs" unless options[:skip_active_job]
40
40
 
41
41
  unless api?
@@ -66,12 +66,19 @@ module Rails
66
66
  template "gitignore", ".gitignore"
67
67
  end
68
68
 
69
+ def cifiles
70
+ empty_directory ".github/workflows"
71
+ template "github/ci.yml", ".github/workflows/ci.yml"
72
+ template "github/dependabot.yml", ".github/dependabot.yml"
73
+ end
74
+
75
+ def rubocop
76
+ template "rubocop.yml", ".rubocop.yml"
77
+ end
78
+
69
79
  def version_control
70
80
  if !options[:skip_git] && !options[:pretend]
71
- run "git init", capture: options[:quiet], abort_on_failure: false
72
- if user_default_branch.strip.empty?
73
- `git symbolic-ref HEAD refs/heads/main`
74
- end
81
+ run git_init_command, capture: options[:quiet], abort_on_failure: false
75
82
  end
76
83
  end
77
84
 
@@ -115,9 +122,12 @@ module Rails
115
122
  def generate_test_dummy(force = false)
116
123
  opts = options.transform_keys(&:to_sym).except(*DUMMY_IGNORE_OPTIONS)
117
124
  opts[:force] = force
125
+ opts[:skip_brakeman] = true
118
126
  opts[:skip_bundle] = true
127
+ opts[:skip_ci] = true
119
128
  opts[:skip_git] = true
120
129
  opts[:skip_hotwire] = true
130
+ opts[:skip_rubocop] = true
121
131
  opts[:dummy_app] = true
122
132
 
123
133
  invoke Rails::Generators::AppGenerator,
@@ -127,10 +137,6 @@ module Rails
127
137
  def test_dummy_config
128
138
  template "rails/boot.rb", "#{dummy_path}/config/boot.rb", force: true
129
139
 
130
- insert_into_file "#{dummy_path}/config/application.rb", <<~RUBY, after: /^Bundler\.require.+\n/
131
- require #{namespaced_name.inspect}
132
- RUBY
133
-
134
140
  if mountable?
135
141
  template "rails/routes.rb", "#{dummy_path}/config/routes.rb", force: true
136
142
  end
@@ -151,7 +157,7 @@ module Rails
151
157
  def test_dummy_clean
152
158
  inside dummy_path do
153
159
  remove_file ".ruby-version"
154
- remove_file "db/seeds.rb"
160
+ remove_dir "db"
155
161
  remove_file "Gemfile"
156
162
  remove_file "lib/tasks"
157
163
  remove_file "public/robots.txt"
@@ -174,12 +180,12 @@ module Rails
174
180
  end
175
181
  end
176
182
 
177
- def bin(force = false)
178
- bin_file = engine? ? "bin/rails.tt" : "bin/test.tt"
179
- template bin_file, force: force do |content|
183
+ def bin
184
+ exclude_pattern = Regexp.union([(engine? ? /test\.tt/ : /rails\.tt/), (/rubocop/ if skip_rubocop?)].compact)
185
+ directory "bin", { exclude_pattern: exclude_pattern } do |content|
180
186
  "#{shebang}\n" + content
181
187
  end
182
- chmod "bin", 0755, verbose: false
188
+ chmod "bin", 0755 & ~File.umask, verbose: false
183
189
  end
184
190
 
185
191
  def gemfile_entry
@@ -187,15 +193,10 @@ module Rails
187
193
 
188
194
  gemfile_in_app_path = File.join(rails_app_path, "Gemfile")
189
195
  if File.exist? gemfile_in_app_path
190
- entry = "\ngem '#{name}', path: '#{relative_path}'"
196
+ entry = %{\ngem "#{name}", path: "#{relative_path}"}
191
197
  append_file gemfile_in_app_path, entry
192
198
  end
193
199
  end
194
-
195
- private
196
- def user_default_branch
197
- @user_default_branch ||= `git config init.defaultbranch`
198
- end
199
200
  end
200
201
 
201
202
  module Generators
@@ -226,12 +227,14 @@ module Rails
226
227
  def initialize(*args)
227
228
  @dummy_path = nil
228
229
  super
230
+ imply_options
229
231
 
230
232
  if !engine? || !with_dummy_app?
231
233
  self.options = options.merge(skip_asset_pipeline: true).freeze
232
234
  end
233
235
  end
234
236
 
237
+ public_task :report_implied_options
235
238
  public_task :set_default_accessors!
236
239
  public_task :create_root
237
240
 
@@ -253,6 +256,16 @@ module Rails
253
256
  build(:app)
254
257
  end
255
258
 
259
+ def create_rubocop_file
260
+ return if skip_rubocop?
261
+ build(:rubocop)
262
+ end
263
+
264
+ def create_cifiles
265
+ return if skip_ci?
266
+ build(:cifiles)
267
+ end
268
+
256
269
  def create_config_files
257
270
  build(:config)
258
271
  end
@@ -351,7 +364,7 @@ module Rails
351
364
  build(:test_dummy_sprocket_assets) unless skip_sprockets?
352
365
  build(:test_dummy_clean)
353
366
  # ensure that bin/rails has proper dummy_path
354
- build(:bin, true)
367
+ build(:bin)
355
368
  end
356
369
  end
357
370
 
@@ -475,6 +488,14 @@ module Rails
475
488
  return unless inside_application?
476
489
  app_path.delete_prefix("#{rails_app_path}/")
477
490
  end
491
+
492
+ def test_command
493
+ if engine? && !options[:skip_active_record] && with_dummy_app?
494
+ "db:test:prepare test"
495
+ else
496
+ "test"
497
+ end
498
+ end
478
499
  end
479
500
  end
480
501
  end
@@ -3,8 +3,8 @@ require_relative "lib/<%= namespaced_name %>/version"
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = <%= name.inspect %>
5
5
  spec.version = <%= camelized_modules %>::VERSION
6
- spec.authors = [<%= author.inspect %>]
7
- spec.email = [<%= email.inspect %>]
6
+ spec.authors = [ <%= author.inspect %> ]
7
+ spec.email = [ <%= email.inspect %> ]
8
8
  spec.homepage = "TODO"
9
9
  spec.summary = "TODO: Summary of <%= camelized_modules %>."
10
10
  spec.description = "TODO: Description of <%= camelized_modules %>."
@@ -1,5 +1,4 @@
1
1
  source "https://rubygems.org"
2
- git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3
2
  <% unless options[:skip_gemspec] -%>
4
3
 
5
4
  # Specify your gem's dependencies in <%= name %>.gemspec.
@@ -8,12 +7,17 @@ gemspec
8
7
  <% gemfile_entries.each do |gemfile_entry| %>
9
8
  <%= gemfile_entry %>
10
9
  <% end -%>
10
+ <%- unless options.skip_rubocop? -%>
11
+
12
+ # Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/]
13
+ gem "rubocop-rails-omakase", require: false
14
+ <%- end -%>
11
15
  <% if RUBY_ENGINE == "ruby" -%>
12
16
 
13
17
  # Start debugger with binding.b [https://github.com/ruby/debug]
14
18
  # gem "debug", ">= 1.0.0"
15
19
  <% end -%>
16
- <% if RUBY_PLATFORM.match?(/bccwin|cygwin|emx|mingw|mswin|wince|java/) -%>
20
+ <% if RUBY_PLATFORM.match?(/mingw|mswin|java/) -%>
17
21
 
18
- gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]
22
+ gem "tzinfo-data", platforms: %i[ <%= bundler_windows_platforms %> jruby ]
19
23
  <% end -%>
@@ -1,4 +1,4 @@
1
- Copyright <%= Date.today.year %> <%= author %>
1
+ Copyright <%= author %>
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -5,6 +5,8 @@
5
5
  <%%= csrf_meta_tags %>
6
6
  <%%= csp_meta_tag %>
7
7
 
8
+ <%%= yield :head %>
9
+
8
10
  <%%= stylesheet_link_tag "<%= namespaced_name %>/application", media: "all" %>
9
11
  </head>
10
12
  <body>
@@ -11,21 +11,5 @@ APP_PATH = File.expand_path("../<%= dummy_path -%>/config/application", __dir__)
11
11
  ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
12
  require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
13
13
 
14
- <% if include_all_railties? -%>
15
- require "rails/all"
16
- <% else -%>
17
- require "rails"
18
- # Pick the frameworks you want:
19
- require "active_model/railtie"
20
- <%= comment_if :skip_active_job %>require "active_job/railtie"
21
- <%= comment_if :skip_active_record %>require "active_record/railtie"
22
- <%= comment_if :skip_active_storage %>require "active_storage/engine"
23
- require "action_controller/railtie"
24
- <%= comment_if :skip_action_mailer %>require "action_mailer/railtie"
25
- <%= comment_if :skip_action_mailbox %>require "action_mailbox/engine"
26
- <%= comment_if :skip_action_text %>require "action_text/engine"
27
- require "action_view/railtie"
28
- <%= comment_if :skip_action_cable %>require "action_cable/engine"
29
- <%= comment_if :skip_test %>require "rails/test_unit/railtie"
30
- <% end -%>
14
+ <%= rails_require_statement %>
31
15
  require "rails/engine/commands"
@@ -0,0 +1,7 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ # explicit rubocop config increases performance slightly while avoiding config confusion.
5
+ ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__))
6
+
7
+ load Gem.bin_path("rubocop", "rubocop")
@@ -0,0 +1,103 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [ main ]
7
+
8
+ jobs:
9
+ <%- unless skip_rubocop? -%>
10
+ lint:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout code
14
+ uses: actions/checkout@v4
15
+
16
+ - name: Set up Ruby
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: <%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" %>
20
+ bundler-cache: true
21
+
22
+ - name: Lint code for consistent style
23
+ run: bin/rubocop -f github
24
+
25
+ <% end -%>
26
+ <% unless options[:skip_test] -%>
27
+ test:
28
+ runs-on: ubuntu-latest
29
+
30
+ <%- if options[:database] == "sqlite3" -%>
31
+ # services:
32
+ # redis:
33
+ # image: redis
34
+ # ports:
35
+ # - 6379:6379
36
+ # options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
37
+ <%- else -%>
38
+ services:
39
+ <%- if options[:database] == "mysql" || options[:database] == "trilogy" -%>
40
+ mysql:
41
+ image: mysql
42
+ env:
43
+ MYSQL_ALLOW_EMPTY_PASSWORD: true
44
+ ports:
45
+ - 3306:3306
46
+ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
47
+ <%- elsif options[:database] == "postgresql" -%>
48
+ postgres:
49
+ image: postgres
50
+ env:
51
+ POSTGRES_USER: postgres
52
+ POSTGRES_PASSWORD: postgres
53
+ ports:
54
+ - 5432:5432
55
+ options: --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3
56
+ <%- end -%>
57
+
58
+ # redis:
59
+ # image: redis
60
+ # ports:
61
+ # - 6379:6379
62
+ # options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
63
+
64
+ <%- end -%>
65
+ steps:
66
+ - name: Install packages
67
+ run: sudo apt-get update && sudo apt-get install --no-install-recommends -y google-chrome-stable <%= dockerfile_base_packages.join(" ") %>
68
+
69
+ - name: Checkout code
70
+ uses: actions/checkout@v4
71
+
72
+ - name: Set up Ruby
73
+ uses: ruby/setup-ruby@v1
74
+ with:
75
+ ruby-version: <%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" %>
76
+ bundler-cache: true
77
+ <%- if using_bun? -%>
78
+
79
+ - uses: oven-sh/setup-bun@v1
80
+ with:
81
+ bun-version: <%= dockerfile_bun_version %>
82
+ <%- end -%>
83
+
84
+ - name: Run tests
85
+ env:
86
+ RAILS_ENV: test
87
+ <%- if options[:database] == "mysql" || options[:database] == "trilogy" -%>
88
+ DATABASE_URL: mysql2://127.0.0.1:3306
89
+ <%- elsif options[:database] == "postgresql" -%>
90
+ DATABASE_URL: postgres://postgres:postgres@localhost:5432
91
+ <%- end -%>
92
+ # REDIS_URL: redis://localhost:6379/0
93
+ run: bin/rails <%= test_command %>
94
+
95
+ - name: Keep screenshots from failed system tests
96
+ uses: actions/upload-artifact@v4
97
+ if: failure()
98
+ with:
99
+ name: screenshots
100
+ path: ${{ github.workspace }}/tmp/screenshots
101
+ if-no-files-found: ignore
102
+ <% end -%>
103
+
@@ -0,0 +1,12 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ open-pull-requests-limit: 10
8
+ - package-ecosystem: github-actions
9
+ directory: "/"
10
+ schedule:
11
+ interval: daily
12
+ open-pull-requests-limit: 10
@@ -9,8 +9,6 @@
9
9
  /<%= dummy_path %>/db/*.sqlite3-*
10
10
  <% end -%>
11
11
  /<%= dummy_path %>/log/*.log
12
- <% unless skip_active_storage? -%>
13
12
  /<%= dummy_path %>/storage/
14
- <% end -%>
15
13
  /<%= dummy_path %>/tmp/
16
14
  <% end -%>
@@ -0,0 +1,8 @@
1
+ # Omakase Ruby styling for Rails
2
+ inherit_gem: { rubocop-rails-omakase: rubocop.yml }
3
+
4
+ # Overwrite or add rules to create your own house style
5
+ #
6
+ # # Use `[a, [b, c]]` not `[ a, [ b, c ] ]`
7
+ # Layout/SpaceInsideArrayLiteralBrackets:
8
+ # Enabled: false
@@ -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
@@ -12,10 +12,10 @@ require "rails/test_help"
12
12
 
13
13
  <% unless options[:skip_active_record] -%>
14
14
  # Load fixtures from the engine
15
- if ActiveSupport::TestCase.respond_to?(:fixture_path=)
16
- ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__)
17
- ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path
18
- ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files"
15
+ if ActiveSupport::TestCase.respond_to?(:fixture_paths=)
16
+ ActiveSupport::TestCase.fixture_paths = [File.expand_path("fixtures", __dir__)]
17
+ ActionDispatch::IntegrationTest.fixture_paths = ActiveSupport::TestCase.fixture_paths
18
+ ActiveSupport::TestCase.file_fixture_path = File.expand_path("fixtures", __dir__) + "/files"
19
19
  ActiveSupport::TestCase.fixtures :all
20
20
  end
21
21
  <% end -%>
@@ -16,6 +16,12 @@ module Rails
16
16
  desc: "Actions for the resource controller"
17
17
 
18
18
  hook_for :resource_route, required: true
19
+
20
+ class << self
21
+ def desc(description = nil)
22
+ ERB.new(File.read(usage_path)).result(binding)
23
+ end
24
+ end
19
25
  end
20
26
  end
21
27
  end
@@ -8,7 +8,8 @@ module Rails
8
8
  remove_hook_for :resource_controller
9
9
  remove_class_option :actions
10
10
 
11
- class_option :api, type: :boolean
11
+ class_option :api, type: :boolean,
12
+ desc: "Generate API-only controller and tests, with no view templates"
12
13
  class_option :resource_route, type: :boolean
13
14
 
14
15
  hook_for :scaffold_controller, required: true
@@ -13,7 +13,7 @@ module Rails
13
13
  class_option :orm, banner: "NAME", type: :string, required: true,
14
14
  desc: "ORM to generate the controller for"
15
15
  class_option :api, type: :boolean,
16
- desc: "Generates API controller"
16
+ desc: "Generate API controller"
17
17
 
18
18
  class_option :skip_routes, type: :boolean, desc: "Don't add routes to config/routes.rb."
19
19
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rails/generators"
4
- require "rails/generators/testing/behaviour"
4
+ require "rails/generators/testing/behavior"
5
5
  require "rails/generators/testing/setup_and_teardown"
6
6
  require "rails/generators/testing/assertions"
7
7
  require "fileutils"
@@ -28,7 +28,7 @@ module Rails
28
28
  # setup :prepare_destination
29
29
  # end
30
30
  class TestCase < ActiveSupport::TestCase
31
- include Rails::Generators::Testing::Behaviour
31
+ include Rails::Generators::Testing::Behavior
32
32
  include Rails::Generators::Testing::SetupAndTeardown
33
33
  include Rails::Generators::Testing::Assertions
34
34
  include FileUtils
@@ -2,15 +2,17 @@ require "test_helper"
2
2
 
3
3
  <% module_namespacing do -%>
4
4
  class <%= class_name %>MailerTest < ActionMailer::TestCase
5
- <% actions.each do |action| -%>
5
+ <% actions.each_with_index do |action, index| -%>
6
+ <% if index != 0 -%>
7
+
8
+ <% end -%>
6
9
  test "<%= action %>" do
7
10
  mail = <%= class_name %>Mailer.<%= action %>
8
11
  assert_equal <%= action.to_s.humanize.inspect %>, mail.subject
9
- assert_equal ["to@example.org"], mail.to
10
- assert_equal ["from@example.com"], mail.from
12
+ assert_equal [ "to@example.org" ], mail.to
13
+ assert_equal [ "from@example.com" ], mail.from
11
14
  assert_match "Hi", mail.body.encoded
12
15
  end
13
-
14
16
  <% end -%>
15
17
  <% if actions.blank? -%>
16
18
  # test "the truth" do
@@ -1,13 +1,14 @@
1
1
  <% module_namespacing do -%>
2
2
  # Preview all emails at http://localhost:3000/rails/mailers/<%= file_path %>_mailer
3
3
  class <%= class_name %>MailerPreview < ActionMailer::Preview
4
- <% actions.each do |action| -%>
4
+ <% actions.each_with_index do |action, index| -%>
5
+ <% if index != 0 -%>
5
6
 
7
+ <% end -%>
6
8
  # Preview this email at http://localhost:3000/rails/mailers/<%= file_path %>_mailer/<%= action %>
7
9
  def <%= action %>
8
10
  <%= class_name %>Mailer.<%= action %>
9
11
  end
10
12
  <% end -%>
11
-
12
13
  end
13
14
  <% end -%>
@@ -11,7 +11,7 @@ module TestUnit # :nodoc:
11
11
  check_class_collision suffix: "ControllerTest"
12
12
 
13
13
  class_option :api, type: :boolean,
14
- desc: "Generates API functional tests"
14
+ desc: "Generate API functional tests"
15
15
 
16
16
  class_option :system_tests, type: :string,
17
17
  desc: "Skip system test files"
@@ -39,7 +39,11 @@ module TestUnit # :nodoc:
39
39
 
40
40
  private
41
41
  def attributes_string
42
- attributes_hash.map { |k, v| "#{k}: #{v}" }.join(", ")
42
+ if attributes_hash.empty?
43
+ "{}"
44
+ else
45
+ "{ #{attributes_hash.map { |k, v| "#{k}: #{v}" }.join(", ")} }"
46
+ end
43
47
  end
44
48
 
45
49
  def attributes_hash
@@ -63,6 +67,16 @@ module TestUnit # :nodoc:
63
67
  attribute = attributes.find { |attr| attr.name == name }
64
68
  attribute&.virtual?
65
69
  end
70
+
71
+ def datetime?(name)
72
+ attribute = attributes.find { |attr| attr.name == name }
73
+ attribute&.type == :datetime
74
+ end
75
+
76
+ def time?(name)
77
+ attribute = attributes.find { |attr| attr.name == name }
78
+ attribute&.type == :time
79
+ end
66
80
  end
67
81
  end
68
82
  end
@@ -17,7 +17,7 @@ class <%= controller_class_name %>ControllerTest < ActionDispatch::IntegrationTe
17
17
 
18
18
  test "should create <%= singular_table_name %>" do
19
19
  assert_difference("<%= class_name %>.count") do
20
- post <%= index_helper %>_url, params: { <%= "#{singular_table_name}: { #{attributes_string} }" %> }, as: :json
20
+ post <%= index_helper %>_url, params: { <%= "#{singular_table_name}: #{attributes_string}" %> }, as: :json
21
21
  end
22
22
 
23
23
  assert_response :created
@@ -29,7 +29,7 @@ class <%= controller_class_name %>ControllerTest < ActionDispatch::IntegrationTe
29
29
  end
30
30
 
31
31
  test "should update <%= singular_table_name %>" do
32
- patch <%= show_helper %>, params: { <%= "#{singular_table_name}: { #{attributes_string} }" %> }, as: :json
32
+ patch <%= show_helper %>, params: { <%= "#{singular_table_name}: #{attributes_string}" %> }, as: :json
33
33
  assert_response :success
34
34
  end
35
35
 
@@ -22,7 +22,7 @@ class <%= controller_class_name %>ControllerTest < ActionDispatch::IntegrationTe
22
22
 
23
23
  test "should create <%= singular_table_name %>" do
24
24
  assert_difference("<%= class_name %>.count") do
25
- post <%= index_helper(type: :url) %>, params: { <%= "#{singular_table_name}: { #{attributes_string} }" %> }
25
+ post <%= index_helper(type: :url) %>, params: { <%= "#{singular_table_name}: #{attributes_string}" %> }
26
26
  end
27
27
 
28
28
  assert_redirected_to <%= show_helper("#{class_name}.last") %>
@@ -39,7 +39,7 @@ class <%= controller_class_name %>ControllerTest < ActionDispatch::IntegrationTe
39
39
  end
40
40
 
41
41
  test "should update <%= singular_table_name %>" do
42
- patch <%= show_helper %>, params: { <%= "#{singular_table_name}: { #{attributes_string} }" %> }
42
+ patch <%= show_helper %>, params: { <%= "#{singular_table_name}: #{attributes_string}" %> }
43
43
  assert_redirected_to <%= show_helper %>
44
44
  end
45
45
 
@@ -35,6 +35,8 @@ class <%= class_name.pluralize %>Test < ApplicationSystemTestCase
35
35
  <%- attributes_hash.each do |attr, value| -%>
36
36
  <%- if boolean?(attr) -%>
37
37
  check "<%= attr.humanize %>" if <%= value %>
38
+ <%- elsif datetime?(attr) || time?(attr) -%>
39
+ fill_in "<%= attr.humanize %>", with: <%= value %>.to_s
38
40
  <%- else -%>
39
41
  fill_in "<%= attr.humanize %>", with: <%= value %>
40
42
  <%- end -%>
@@ -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
@@ -11,7 +11,7 @@ require "rails/generators"
11
11
  module Rails
12
12
  module Generators
13
13
  module Testing
14
- module Behaviour
14
+ module Behavior
15
15
  extend ActiveSupport::Concern
16
16
  include ActiveSupport::Testing::Stream
17
17
 
@@ -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