railties 6.1.0 → 7.0.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 (161) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +121 -276
  3. data/MIT-LICENSE +1 -1
  4. data/RDOC_MAIN.rdoc +16 -16
  5. data/README.rdoc +1 -2
  6. data/lib/rails/all.rb +0 -1
  7. data/lib/rails/api/task.rb +1 -1
  8. data/lib/rails/app_updater.rb +3 -5
  9. data/lib/rails/application/bootstrap.rb +21 -5
  10. data/lib/rails/application/configuration.rb +79 -33
  11. data/lib/rails/application/default_middleware_stack.rb +7 -3
  12. data/lib/rails/application/finisher.rb +42 -85
  13. data/lib/rails/application/routes_reloader.rb +8 -0
  14. data/lib/rails/application.rb +32 -51
  15. data/lib/rails/application_controller.rb +2 -2
  16. data/lib/rails/autoloaders/inflector.rb +21 -0
  17. data/lib/rails/autoloaders.rb +12 -16
  18. data/lib/rails/code_statistics.rb +2 -2
  19. data/lib/rails/code_statistics_calculator.rb +10 -1
  20. data/lib/rails/command/base.rb +26 -12
  21. data/lib/rails/command/behavior.rb +1 -1
  22. data/lib/rails/command/environment_argument.rb +1 -1
  23. data/lib/rails/command.rb +11 -10
  24. data/lib/rails/commands/credentials/USAGE +4 -2
  25. data/lib/rails/commands/credentials/credentials_command/diffing.rb +26 -16
  26. data/lib/rails/commands/credentials/credentials_command.rb +8 -3
  27. data/lib/rails/commands/dbconsole/dbconsole_command.rb +10 -11
  28. data/lib/rails/commands/help/USAGE +3 -2
  29. data/lib/rails/commands/notes/notes_command.rb +2 -2
  30. data/lib/rails/commands/runner/runner_command.rb +3 -2
  31. data/lib/rails/commands/server/server_command.rb +2 -5
  32. data/lib/rails/configuration.rb +18 -23
  33. data/lib/rails/engine/configuration.rb +3 -3
  34. data/lib/rails/engine.rb +18 -24
  35. data/lib/rails/gem_version.rb +2 -2
  36. data/lib/rails/generators/actions/create_migration.rb +4 -4
  37. data/lib/rails/generators/actions.rb +35 -13
  38. data/lib/rails/generators/app_base.rb +140 -102
  39. data/lib/rails/generators/app_name.rb +1 -1
  40. data/lib/rails/generators/base.rb +9 -13
  41. data/lib/rails/generators/erb/scaffold/scaffold_generator.rb +2 -0
  42. data/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt +8 -8
  43. data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +8 -4
  44. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +11 -28
  45. data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +7 -3
  46. data/lib/rails/generators/erb/scaffold/templates/partial.html.erb.tt +17 -0
  47. data/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt +8 -17
  48. data/lib/rails/generators/erb.rb +1 -1
  49. data/lib/rails/generators/generated_attribute.rb +45 -9
  50. data/lib/rails/generators/migration.rb +2 -6
  51. data/lib/rails/generators/model_helpers.rb +1 -1
  52. data/lib/rails/generators/named_base.rb +11 -11
  53. data/lib/rails/generators/rails/app/app_generator.rb +54 -93
  54. data/lib/rails/generators/rails/app/templates/Gemfile.tt +42 -52
  55. data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css.tt +2 -2
  56. data/lib/rails/generators/rails/app/templates/app/mailers/application_mailer.rb.tt +2 -2
  57. data/lib/rails/generators/rails/app/templates/app/models/application_record.rb.tt +1 -1
  58. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +3 -9
  59. data/lib/rails/generators/rails/app/templates/bin/rails.tt +1 -4
  60. data/lib/rails/generators/rails/app/templates/bin/rake.tt +0 -3
  61. data/lib/rails/generators/rails/app/templates/bin/setup.tt +9 -14
  62. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +0 -1
  63. data/lib/rails/generators/rails/app/templates/config/boot.rb.tt +1 -1
  64. data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +2 -2
  65. data/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt +3 -3
  66. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +3 -3
  67. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +2 -2
  68. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +3 -3
  69. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +2 -2
  70. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +3 -3
  71. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +1 -1
  72. data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +5 -5
  73. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +6 -12
  74. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +11 -38
  75. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +6 -11
  76. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +1 -5
  77. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +19 -25
  78. data/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt +2 -2
  79. data/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb.tt +4 -4
  80. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt +117 -0
  81. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +3 -3
  82. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +1 -1
  83. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +4 -1
  84. data/lib/rails/generators/rails/app/templates/config/storage.yml.tt +5 -5
  85. data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +2 -2
  86. data/lib/rails/generators/rails/app/templates/gitattributes.tt +0 -5
  87. data/lib/rails/generators/rails/app/templates/gitignore.tt +3 -1
  88. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +1 -1
  89. data/lib/rails/generators/rails/controller/controller_generator.rb +1 -2
  90. data/lib/rails/generators/rails/controller/templates/controller.rb.tt +0 -4
  91. data/lib/rails/generators/rails/db/system/change/change_generator.rb +1 -1
  92. data/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt +1 -1
  93. data/lib/rails/generators/rails/plugin/plugin_generator.rb +42 -24
  94. data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +7 -3
  95. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +11 -20
  96. data/lib/rails/generators/rails/plugin/templates/README.md.tt +1 -1
  97. data/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt +2 -2
  98. data/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +0 -3
  99. data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +4 -5
  100. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +0 -5
  101. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt +2 -2
  102. data/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb.tt +1 -1
  103. data/lib/rails/generators/rails/plugin/templates/rails/boot.rb.tt +2 -2
  104. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +2 -7
  105. data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +0 -19
  106. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +1 -5
  107. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +6 -10
  108. data/lib/rails/generators/resource_helpers.rb +2 -2
  109. data/lib/rails/generators/test_unit/generator/templates/generator_test.rb.tt +1 -1
  110. data/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt +2 -2
  111. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +3 -3
  112. data/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt +5 -5
  113. data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +7 -7
  114. data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +9 -11
  115. data/lib/rails/generators/testing/behaviour.rb +3 -4
  116. data/lib/rails/generators.rb +9 -22
  117. data/lib/rails/info.rb +1 -1
  118. data/lib/rails/info_controller.rb +1 -3
  119. data/lib/rails/initializable.rb +1 -1
  120. data/lib/rails/mailers_controller.rb +2 -4
  121. data/lib/rails/rack/logger.rb +0 -1
  122. data/lib/rails/railtie/configuration.rb +1 -2
  123. data/lib/rails/railtie.rb +31 -14
  124. data/lib/rails/ruby_version_check.rb +3 -3
  125. data/lib/rails/secrets.rb +4 -1
  126. data/lib/rails/source_annotation_extractor.rb +1 -1
  127. data/lib/rails/tasks/framework.rake +2 -8
  128. data/lib/rails/tasks/statistics.rake +3 -1
  129. data/lib/rails/tasks/tmp.rake +8 -1
  130. data/lib/rails/tasks/yarn.rake +10 -7
  131. data/lib/rails/tasks/zeitwerk.rake +2 -10
  132. data/lib/rails/templates/layouts/application.html.erb +15 -0
  133. data/lib/rails/templates/rails/mailers/email.html.erb +13 -11
  134. data/lib/rails/templates/rails/welcome/index.html.erb +62 -47
  135. data/lib/rails/test_unit/railtie.rb +0 -4
  136. data/lib/rails/test_unit/runner.rb +16 -9
  137. data/lib/rails/test_unit/testing.rake +4 -9
  138. data/lib/rails/welcome_controller.rb +1 -0
  139. data/lib/rails.rb +5 -0
  140. metadata +33 -36
  141. data/lib/rails/command/spellchecker.rb +0 -57
  142. data/lib/rails/generators/css/assets/assets_generator.rb +0 -15
  143. data/lib/rails/generators/css/assets/templates/stylesheet.css +0 -4
  144. data/lib/rails/generators/css/scaffold/scaffold_generator.rb +0 -18
  145. data/lib/rails/generators/rails/app/templates/app/javascript/channels/consumer.js +0 -6
  146. data/lib/rails/generators/rails/app/templates/app/javascript/channels/index.js +0 -5
  147. data/lib/rails/generators/rails/app/templates/app/javascript/packs/application.js.tt +0 -23
  148. data/lib/rails/generators/rails/app/templates/bin/spring.tt +0 -9
  149. data/lib/rails/generators/rails/app/templates/bin/yarn.tt +0 -18
  150. data/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb.tt +0 -8
  151. data/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt +0 -8
  152. data/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb.tt +0 -5
  153. data/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb.tt +0 -4
  154. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_1.rb.tt +0 -63
  155. data/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt +0 -16
  156. data/lib/rails/generators/rails/app/templates/config/spring.rb.tt +0 -6
  157. data/lib/rails/generators/rails/app/templates/package.json.tt +0 -11
  158. data/lib/rails/generators/rails/assets/USAGE +0 -16
  159. data/lib/rails/generators/rails/assets/assets_generator.rb +0 -26
  160. data/lib/rails/generators/rails/assets/templates/stylesheet.css +0 -4
  161. data/lib/rails/generators/rails/scaffold/templates/scaffold.css +0 -80
@@ -30,9 +30,6 @@ module Rails
30
30
  class_option :database, type: :string, aliases: "-d", default: "sqlite3",
31
31
  desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})"
32
32
 
33
- class_option :skip_gemfile, type: :boolean, default: false,
34
- desc: "Don't create a Gemfile"
35
-
36
33
  class_option :skip_git, type: :boolean, aliases: "-G", default: false,
37
34
  desc: "Skip .gitignore file"
38
35
 
@@ -58,26 +55,19 @@ module Rails
58
55
  class_option :skip_active_storage, type: :boolean, default: false,
59
56
  desc: "Skip Active Storage files"
60
57
 
61
- class_option :skip_puma, type: :boolean, aliases: "-P", default: false,
62
- desc: "Skip Puma related files"
63
-
64
58
  class_option :skip_action_cable, type: :boolean, aliases: "-C", default: false,
65
59
  desc: "Skip Action Cable files"
66
60
 
67
- class_option :skip_sprockets, type: :boolean, aliases: "-S", default: false,
68
- desc: "Skip Sprockets files"
69
-
70
- class_option :skip_spring, type: :boolean, default: false,
71
- desc: "Don't install Spring application preloader"
61
+ class_option :skip_asset_pipeline, type: :boolean, aliases: "-A", default: false
72
62
 
73
- class_option :skip_listen, type: :boolean, default: false,
74
- desc: "Don't generate configuration that depends on the listen gem"
63
+ class_option :asset_pipeline, type: :string, aliases: "-a", default: "sprockets",
64
+ desc: "Choose your asset pipeline [options: sprockets (default), propshaft]"
75
65
 
76
66
  class_option :skip_javascript, type: :boolean, aliases: "-J", default: name == "plugin",
77
67
  desc: "Skip JavaScript files"
78
68
 
79
- class_option :skip_turbolinks, type: :boolean, default: false,
80
- desc: "Skip turbolinks gem"
69
+ class_option :skip_hotwire, type: :boolean, default: false,
70
+ desc: "Skip Hotwire integration"
81
71
 
82
72
  class_option :skip_jbuilder, type: :boolean, default: false,
83
73
  desc: "Skip jbuilder gem"
@@ -97,8 +87,8 @@ module Rails
97
87
  class_option :edge, type: :boolean, default: false,
98
88
  desc: "Set up the #{name} with Gemfile pointing to Rails repository"
99
89
 
100
- class_option :master, type: :boolean, default: false,
101
- desc: "Set up the #{name} with Gemfile pointing to Rails repository master branch"
90
+ class_option :main, type: :boolean, default: false, aliases: "--master",
91
+ desc: "Set up the #{name} with Gemfile pointing to Rails repository main branch"
102
92
 
103
93
  class_option :rc, type: :string, default: nil,
104
94
  desc: "Path to file containing extra configuration options for rails command"
@@ -110,46 +100,24 @@ module Rails
110
100
  desc: "Show this help message and quit"
111
101
  end
112
102
 
113
- def initialize(*args)
114
- @gem_filter = lambda { |gem| true }
115
- @extra_entries = []
103
+ def initialize(positional_argv, option_argv, *)
104
+ @argv = [*positional_argv, *option_argv]
105
+ @gem_filter = lambda { |gem| true }
116
106
  super
117
107
  end
118
108
 
119
109
  private
120
- def gemfile_entry(name, *args) # :doc:
121
- options = args.extract_options!
122
- version = args.first
123
- github = options[:github]
124
- path = options[:path]
125
-
126
- if github
127
- @extra_entries << GemfileEntry.github(name, github)
128
- elsif path
129
- @extra_entries << GemfileEntry.path(name, path)
130
- else
131
- @extra_entries << GemfileEntry.version(name, version)
132
- end
133
- self
134
- end
135
-
136
110
  def gemfile_entries # :doc:
137
111
  [rails_gemfile_entry,
112
+ asset_pipeline_gemfile_entry,
138
113
  database_gemfile_entry,
139
114
  web_server_gemfile_entry,
140
- assets_gemfile_entry,
141
- webpacker_gemfile_entry,
142
115
  javascript_gemfile_entry,
116
+ hotwire_gemfile_entry,
117
+ css_gemfile_entry,
143
118
  jbuilder_gemfile_entry,
144
119
  psych_gemfile_entry,
145
- cable_gemfile_entry,
146
- @extra_entries].flatten.find_all(&@gem_filter)
147
- end
148
-
149
- def add_gem_entry_filter # :doc:
150
- @gem_filter = lambda { |next_filter, entry|
151
- yield(entry) && next_filter.call(entry)
152
- }.curry[@gem_filter]
120
+ cable_gemfile_entry].flatten.find_all(&@gem_filter)
153
121
  end
154
122
 
155
123
  def builder # :doc:
@@ -184,7 +152,7 @@ module Rails
184
152
  when /^https?:\/\//
185
153
  options[:template]
186
154
  when String
187
- File.expand_path(options[:template], Dir.pwd)
155
+ File.expand_path(`echo #{options[:template]}`.strip)
188
156
  else
189
157
  options[:template]
190
158
  end
@@ -194,13 +162,24 @@ module Rails
194
162
  return [] if options[:skip_active_record]
195
163
  gem_name, gem_version = gem_for_database
196
164
  GemfileEntry.version gem_name, gem_version,
197
- "Use #{options[:database]} as the database for Active Record"
165
+ "Use #{options[:database]} as the database for Active Record"
198
166
  end
199
167
 
200
168
  def web_server_gemfile_entry # :doc:
201
- return [] if options[:skip_puma]
202
- comment = "Use Puma as the app server"
203
- GemfileEntry.new("puma", "~> 5.0", comment)
169
+ GemfileEntry.new "puma", "~> 5.0", "Use the Puma web server [https://github.com/puma/puma]"
170
+ end
171
+
172
+ def asset_pipeline_gemfile_entry
173
+ return [] if options[:skip_asset_pipeline]
174
+
175
+ if options[:asset_pipeline] == "sprockets"
176
+ GemfileEntry.floats "sprockets-rails",
177
+ "The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]"
178
+ elsif options[:asset_pipeline] == "propshaft"
179
+ GemfileEntry.floats "propshaft", "The modern asset pipeline for Rails [https://github.com/rails/propshaft]"
180
+ else
181
+ []
182
+ end
204
183
  end
205
184
 
206
185
  def include_all_railties? # :doc:
@@ -209,7 +188,6 @@ module Rails
209
188
  :skip_active_record,
210
189
  :skip_action_mailer,
211
190
  :skip_test,
212
- :skip_sprockets,
213
191
  :skip_action_cable,
214
192
  :skip_active_job
215
193
  ),
@@ -256,6 +234,11 @@ module Rails
256
234
  options[:skip_dev_gems]
257
235
  end
258
236
 
237
+ def skip_sprockets?
238
+ options[:skip_asset_pipeline] || options[:asset_pipeline] != "sprockets"
239
+ end
240
+
241
+
259
242
  class GemfileEntry < Struct.new(:name, :version, :comment, :options, :commented_out)
260
243
  def initialize(name, version, comment, options = {}, commented_out = false)
261
244
  super
@@ -273,6 +256,10 @@ module Rails
273
256
  new(name, version, comment)
274
257
  end
275
258
 
259
+ def self.floats(name, comment = nil)
260
+ new(name, nil, comment)
261
+ end
262
+
276
263
  def self.path(name, path, comment = nil)
277
264
  new(name, nil, comment, path: path)
278
265
  end
@@ -281,30 +268,35 @@ module Rails
281
268
  version = super
282
269
 
283
270
  if version.is_a?(Array)
284
- version.join("', '")
271
+ version.join('", "')
285
272
  else
286
273
  version
287
274
  end
288
275
  end
276
+
277
+ def to_s
278
+ [ ("# #{comment}\n" if comment),
279
+ ("# " if commented_out), "gem \"#{name}\"", (", \"#{version}\"" if version),
280
+ *options.map { |key, val| ", #{key}: #{val.inspect}" }
281
+ ].compact.join
282
+ end
283
+ end
284
+
285
+ def rails_prerelease?
286
+ options.dev? || options.edge? || options.main?
289
287
  end
290
288
 
291
289
  def rails_gemfile_entry
292
290
  if options.dev?
293
- [
294
- GemfileEntry.path("rails", Rails::Generators::RAILS_DEV_PATH)
295
- ]
291
+ GemfileEntry.path("rails", Rails::Generators::RAILS_DEV_PATH, "Use local checkout of Rails")
296
292
  elsif options.edge?
297
- [
298
- GemfileEntry.github("rails", "rails/rails")
299
- ]
300
- elsif options.master?
301
- [
302
- GemfileEntry.github("rails", "rails/rails", "master")
303
- ]
293
+ edge_branch = Rails.gem_version.prerelease? ? "main" : [*Rails.gem_version.segments.first(2), "stable"].join("-")
294
+ GemfileEntry.github("rails", "rails/rails", edge_branch, "Use specific branch of Rails")
295
+ elsif options.main?
296
+ GemfileEntry.github("rails", "rails/rails", "main", "Use main development branch of Rails")
304
297
  else
305
- [GemfileEntry.version("rails",
306
- rails_version_specifier,
307
- "Bundle edge Rails instead: gem 'rails', github: 'rails/rails'")]
298
+ GemfileEntry.version("rails", rails_version_specifier,
299
+ %(Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"))
308
300
  end
309
301
  end
310
302
 
@@ -321,30 +313,54 @@ module Rails
321
313
  end
322
314
  end
323
315
 
324
- def assets_gemfile_entry
325
- return [] if options[:skip_sprockets]
326
-
327
- GemfileEntry.version("sass-rails", ">= 6", "Use SCSS for stylesheets")
316
+ def jbuilder_gemfile_entry
317
+ return [] if options[:skip_jbuilder]
318
+ GemfileEntry.new "jbuilder", nil, "Build JSON APIs with ease [https://github.com/rails/jbuilder]", {}, options[:api]
328
319
  end
329
320
 
330
- def webpacker_gemfile_entry
321
+ def javascript_gemfile_entry
331
322
  return [] if options[:skip_javascript]
332
323
 
333
- GemfileEntry.version "webpacker", "~> 5.0", "Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker"
324
+ if adjusted_javascript_option == "importmap"
325
+ GemfileEntry.floats "importmap-rails", "Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]"
326
+ else
327
+ GemfileEntry.floats "jsbundling-rails", "Bundle and transpile JavaScript [https://github.com/rails/jsbundling-rails]"
328
+ end
334
329
  end
335
330
 
336
- def jbuilder_gemfile_entry
337
- return [] if options[:skip_jbuilder]
338
- comment = "Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder"
339
- GemfileEntry.new "jbuilder", "~> 2.7", comment, {}, options[:api]
331
+ def hotwire_gemfile_entry
332
+ return [] if options[:skip_javascript] || options[:skip_hotwire]
333
+
334
+ turbo_rails_entry =
335
+ GemfileEntry.floats "turbo-rails", "Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]"
336
+
337
+ stimulus_rails_entry =
338
+ GemfileEntry.floats "stimulus-rails", "Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]"
339
+
340
+ [ turbo_rails_entry, stimulus_rails_entry ]
340
341
  end
341
342
 
342
- def javascript_gemfile_entry
343
- if options[:skip_javascript] || options[:skip_turbolinks]
344
- []
343
+ def using_node?
344
+ options[:javascript] && options[:javascript] != "importmap"
345
+ end
346
+
347
+ # CSS processors other than Tailwind require a node-based JavaScript environment. So overwrite the normal JS default
348
+ # if one such processor has been specified.
349
+ def adjusted_javascript_option
350
+ if options[:css] && options[:css] != "tailwind" && options[:javascript] == "importmap"
351
+ "esbuild"
352
+ else
353
+ options[:javascript]
354
+ end
355
+ end
356
+
357
+ def css_gemfile_entry
358
+ return [] unless options[:css]
359
+
360
+ if !using_node? && options[:css] == "tailwind"
361
+ GemfileEntry.floats "tailwindcss-rails", "Use Tailwind CSS [https://github.com/rails/tailwindcss-rails]"
345
362
  else
346
- [ GemfileEntry.version("turbolinks", "~> 5",
347
- "Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks") ]
363
+ GemfileEntry.floats "cssbundling-rails", "Bundle and process CSS [https://github.com/rails/cssbundling-rails]"
348
364
  end
349
365
  end
350
366
 
@@ -391,43 +407,65 @@ module Rails
391
407
  end
392
408
 
393
409
  def bundle_install?
394
- !(options[:skip_gemfile] || options[:skip_bundle] || options[:pretend])
395
- end
396
-
397
- def spring_install?
398
- !options[:skip_spring] && !options.dev? && Process.respond_to?(:fork) && !RUBY_PLATFORM.include?("cygwin")
399
- end
400
-
401
- def webpack_install?
402
- !(options[:skip_javascript] || options[:skip_webpack_install])
410
+ !(options[:skip_bundle] || options[:pretend])
403
411
  end
404
412
 
405
413
  def depends_on_system_test?
406
414
  !(options[:skip_system_test] || options[:skip_test] || options[:api])
407
415
  end
408
416
 
409
- def depend_on_listen?
410
- !options[:skip_listen] && os_supports_listen_out_of_the_box?
411
- end
412
-
413
417
  def depend_on_bootsnap?
414
418
  !options[:skip_bootsnap] && !options[:dev] && !defined?(JRUBY_VERSION)
415
419
  end
416
420
 
417
- def os_supports_listen_out_of_the_box?
418
- /darwin|linux/.match?(RbConfig::CONFIG["host_os"])
421
+ def target_rails_prerelease(self_command = "new")
422
+ return unless rails_prerelease? && bundle_install?
423
+
424
+ if !File.exist?(File.expand_path("Gemfile", destination_root))
425
+ create_file("Gemfile", <<~GEMFILE)
426
+ source "https://rubygems.org"
427
+ git_source(:github) { |repo| "https://github.com/\#{repo}.git" }
428
+ #{rails_gemfile_entry}
429
+ GEMFILE
430
+
431
+ run_bundle
432
+
433
+ @argv[0] = destination_root
434
+ require "shellwords"
435
+ bundle_command("exec rails #{self_command} #{Shellwords.join(@argv)}")
436
+ exit
437
+ else
438
+ remove_file("Gemfile")
439
+ remove_file("Gemfile.lock")
440
+ end
419
441
  end
420
442
 
421
443
  def run_bundle
422
444
  bundle_command("install", "BUNDLE_IGNORE_MESSAGES" => "1") if bundle_install?
423
445
  end
424
446
 
425
- def run_webpack
426
- if webpack_install?
427
- rails_command "webpacker:install"
428
- if options[:webpack] && options[:webpack] != "webpack"
429
- rails_command "webpacker:install:#{options[:webpack]}"
430
- end
447
+ def run_javascript
448
+ return if options[:skip_javascript] || !bundle_install?
449
+
450
+ case adjusted_javascript_option
451
+ when "importmap" then rails_command "importmap:install"
452
+ when "webpack", "esbuild", "rollup" then rails_command "javascript:install:#{adjusted_javascript_option}"
453
+ end
454
+ end
455
+
456
+ def run_hotwire
457
+ return if options[:skip_javascript] || options[:skip_hotwire] || !bundle_install?
458
+
459
+ rails_command "turbo:install stimulus:install"
460
+ end
461
+
462
+ def run_css
463
+ return if !options[:css] || !bundle_install?
464
+
465
+ if !using_node? && options[:css] == "tailwind"
466
+ rails_command "tailwindcss:install"
467
+ else
468
+ rails_command "css:install:#{options[:css]}"
431
469
  end
432
470
  end
433
471
 
@@ -7,7 +7,7 @@ module Rails
7
7
 
8
8
  private
9
9
  def app_name
10
- @app_name ||= original_app_name.tr('\\', "").tr("-. ", "_")
10
+ @app_name ||= original_app_name.tr("\\", "").tr("-. ", "_")
11
11
  end
12
12
 
13
13
  def original_app_name
@@ -206,7 +206,7 @@ module Rails
206
206
  end
207
207
 
208
208
  # Make class option aware of Rails::Generators.options and Rails::Generators.aliases.
209
- def self.class_option(name, options = {}) #:nodoc:
209
+ def self.class_option(name, options = {}) # :nodoc:
210
210
  options[:desc] = "Indicates when to generate #{name.to_s.humanize.downcase}" unless options.key?(:desc)
211
211
  options[:aliases] = default_aliases_for_option(name, options)
212
212
  options[:default] = default_value_for_option(name, options)
@@ -231,7 +231,7 @@ module Rails
231
231
 
232
232
  # Cache source root and add lib/generators/base/generator/templates to
233
233
  # source paths.
234
- def self.inherited(base) #:nodoc:
234
+ def self.inherited(base) # :nodoc:
235
235
  super
236
236
 
237
237
  # Invoke source_root so the default_source_root is set.
@@ -324,21 +324,17 @@ module Rails
324
324
 
325
325
  # Sets the base_name taking into account the current class namespace.
326
326
  def self.base_name # :doc:
327
- @base_name ||= begin
328
- if base = name.to_s.split("::").first
329
- base.underscore
330
- end
327
+ @base_name ||= if base = name.to_s.split("::").first
328
+ base.underscore
331
329
  end
332
330
  end
333
331
 
334
332
  # Removes the namespaces and get the generator name. For example,
335
333
  # Rails::Generators::ModelGenerator will return "model" as generator name.
336
334
  def self.generator_name # :doc:
337
- @generator_name ||= begin
338
- if generator = name.to_s.split("::").last
339
- generator.delete_suffix!("Generator")
340
- generator.underscore
341
- end
335
+ @generator_name ||= if generator = name.to_s.split("::").last
336
+ generator.delete_suffix!("Generator")
337
+ generator.underscore
342
338
  end
343
339
  end
344
340
 
@@ -368,13 +364,13 @@ module Rails
368
364
  end
369
365
 
370
366
  # Keep hooks configuration that are used on prepare_for_invocation.
371
- def self.hooks #:nodoc:
367
+ def self.hooks # :nodoc:
372
368
  @hooks ||= from_superclass(:hooks, {})
373
369
  end
374
370
 
375
371
  # Prepare class invocation to search on Rails namespace if a previous
376
372
  # added hook is being used.
377
- def self.prepare_for_invocation(name, value) #:nodoc:
373
+ def self.prepare_for_invocation(name, value) # :nodoc:
378
374
  return super unless value.is_a?(String) || value.is_a?(Symbol)
379
375
 
380
376
  if value && constants = hooks[name]
@@ -21,6 +21,8 @@ module Erb # :nodoc:
21
21
  template filename, File.join("app/views", controller_file_path, filename)
22
22
  end
23
23
  end
24
+
25
+ template "partial.html.erb", File.join("app/views", controller_file_path, "_#{singular_name}.html.erb")
24
26
  end
25
27
 
26
28
  private
@@ -1,6 +1,6 @@
1
1
  <%%= form_with(model: <%= model_resource_name %>) do |form| %>
2
2
  <%% if <%= singular_table_name %>.errors.any? %>
3
- <div id="error_explanation">
3
+ <div style="color: red">
4
4
  <h2><%%= pluralize(<%= singular_table_name %>.errors.count, "error") %> prohibited this <%= singular_table_name %> from being saved:</h2>
5
5
 
6
6
  <ul>
@@ -12,26 +12,26 @@
12
12
  <%% end %>
13
13
 
14
14
  <% attributes.each do |attribute| -%>
15
- <div class="field">
15
+ <div>
16
16
  <% if attribute.password_digest? -%>
17
- <%%= form.label :password %>
17
+ <%%= form.label :password, style: "display: block" %>
18
18
  <%%= form.password_field :password %>
19
19
  </div>
20
20
 
21
- <div class="field">
22
- <%%= form.label :password_confirmation %>
21
+ <div>
22
+ <%%= form.label :password_confirmation, style: "display: block" %>
23
23
  <%%= form.password_field :password_confirmation %>
24
24
  <% elsif attribute.attachments? -%>
25
- <%%= form.label :<%= attribute.column_name %> %>
25
+ <%%= form.label :<%= attribute.column_name %>, style: "display: block" %>
26
26
  <%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, multiple: true %>
27
27
  <% else -%>
28
- <%%= form.label :<%= attribute.column_name %> %>
28
+ <%%= form.label :<%= attribute.column_name %>, style: "display: block" %>
29
29
  <%%= form.<%= attribute.field_type %> :<%= attribute.column_name %> %>
30
30
  <% end -%>
31
31
  </div>
32
32
 
33
33
  <% end -%>
34
- <div class="actions">
34
+ <div>
35
35
  <%%= form.submit %>
36
36
  </div>
37
37
  <%% end %>
@@ -1,6 +1,10 @@
1
- <h1>Editing <%= singular_table_name.titleize %></h1>
1
+ <h1>Editing <%= human_name.downcase %></h1>
2
2
 
3
- <%%= render 'form', <%= singular_table_name %>: @<%= singular_table_name %> %>
3
+ <%%= render "form", <%= singular_table_name %>: @<%= singular_table_name %> %>
4
4
 
5
- <%%= link_to 'Show', @<%= singular_table_name %> %> |
6
- <%%= link_to 'Back', <%= index_helper %>_path %>
5
+ <br>
6
+
7
+ <div>
8
+ <%%= link_to "Show this <%= human_name.downcase %>", <%= model_resource_name(prefix: "@") %> %> |
9
+ <%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper(type: :path) %> %>
10
+ </div>
@@ -1,31 +1,14 @@
1
- <p id="notice"><%%= notice %></p>
1
+ <p style="color: green"><%%= notice %></p>
2
2
 
3
- <h1><%= plural_table_name.titleize %></h1>
3
+ <h1><%= human_name.pluralize %></h1>
4
4
 
5
- <table>
6
- <thead>
7
- <tr>
8
- <% attributes.reject(&:password_digest?).each do |attribute| -%>
9
- <th><%= attribute.human_name %></th>
10
- <% end -%>
11
- <th colspan="3"></th>
12
- </tr>
13
- </thead>
5
+ <div id="<%= plural_table_name %>">
6
+ <%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %>
7
+ <%%= render <%= singular_table_name %> %>
8
+ <p>
9
+ <%%= link_to "Show this <%= human_name.downcase %>", <%= model_resource_name(singular_table_name) %> %>
10
+ </p>
11
+ <%% end %>
12
+ </div>
14
13
 
15
- <tbody>
16
- <%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %>
17
- <tr>
18
- <% attributes.reject(&:password_digest?).each do |attribute| -%>
19
- <td><%%= <%= singular_table_name %>.<%= attribute.column_name %> %></td>
20
- <% end -%>
21
- <td><%%= link_to 'Show', <%= model_resource_name %> %></td>
22
- <td><%%= link_to 'Edit', edit_<%= singular_route_name %>_path(<%= singular_table_name %>) %></td>
23
- <td><%%= link_to 'Destroy', <%= model_resource_name %>, method: :delete, data: { confirm: 'Are you sure?' } %></td>
24
- </tr>
25
- <%% end %>
26
- </tbody>
27
- </table>
28
-
29
- <br>
30
-
31
- <%%= link_to 'New <%= singular_table_name.titleize %>', new_<%= singular_route_name %>_path %>
14
+ <%%= link_to "New <%= human_name.downcase %>", <%= new_helper(type: :path) %> %>
@@ -1,5 +1,9 @@
1
- <h1>New <%= singular_table_name.titleize %></h1>
1
+ <h1>New <%= human_name.downcase %></h1>
2
2
 
3
- <%%= render 'form', <%= singular_table_name %>: @<%= singular_table_name %> %>
3
+ <%%= render "form", <%= singular_table_name %>: @<%= singular_table_name %> %>
4
4
 
5
- <%%= link_to 'Back', <%= index_helper %>_path %>
5
+ <br>
6
+
7
+ <div>
8
+ <%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper(type: :path) %> %>
9
+ </div>
@@ -0,0 +1,17 @@
1
+ <div id="<%%= dom_id <%= singular_name %> %>">
2
+ <% attributes.reject(&:password_digest?).each do |attribute| -%>
3
+ <p>
4
+ <strong><%= attribute.human_name %>:</strong>
5
+ <% if attribute.attachment? -%>
6
+ <%%= link_to <%= singular_name %>.<%= attribute.column_name %>.filename, <%= singular_name %>.<%= attribute.column_name %> if <%= singular_name %>.<%= attribute.column_name %>.attached? %>
7
+ <% elsif attribute.attachments? -%>
8
+ <%% <%= singular_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %>
9
+ <div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %> %></div>
10
+ <%% end %>
11
+ <% else -%>
12
+ <%%= <%= singular_name %>.<%= attribute.column_name %> %>
13
+ <% end -%>
14
+ </p>
15
+
16
+ <% end -%>
17
+ </div>
@@ -1,19 +1,10 @@
1
- <p id="notice"><%%= notice %></p>
1
+ <p style="color: green"><%%= notice %></p>
2
2
 
3
- <% attributes.reject(&:password_digest?).each do |attribute| -%>
4
- <p>
5
- <strong><%= attribute.human_name %>:</strong>
6
- <% if attribute.attachment? -%>
7
- <%%= link_to @<%= singular_table_name %>.<%= attribute.column_name %>.filename, @<%= singular_table_name %>.<%= attribute.column_name %> if @<%= singular_table_name %>.<%= attribute.column_name %>.attached? %>
8
- <% elsif attribute.attachments? -%>
9
- <%% @<%= singular_table_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %>
10
- <div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %> %></div>
11
- <%% end %>
12
- <% else -%>
13
- <%%= @<%= singular_table_name %>.<%= attribute.column_name %> %>
14
- <% end -%>
15
- </p>
3
+ <%%= render @<%= singular_table_name %> %>
16
4
 
17
- <% end -%>
18
- <%%= link_to 'Edit', edit_<%= singular_table_name %>_path(@<%= singular_table_name %>) %> |
19
- <%%= link_to 'Back', <%= index_helper %>_path %>
5
+ <div>
6
+ <%%= link_to "Edit this <%= human_name.downcase %>", <%= edit_helper(type: :path) %> %> |
7
+ <%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper(type: :path) %> %>
8
+
9
+ <%%= button_to "Destroy this <%= human_name.downcase %>", <%= model_resource_name(prefix: "@") %>, method: :delete %>
10
+ </div>
@@ -4,7 +4,7 @@ require "rails/generators/named_base"
4
4
 
5
5
  module Erb # :nodoc:
6
6
  module Generators # :nodoc:
7
- class Base < Rails::Generators::NamedBase #:nodoc:
7
+ class Base < Rails::Generators::NamedBase # :nodoc:
8
8
  private
9
9
  def formats
10
10
  [format]