railties 7.0.0.rc2 → 7.0.2

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/MIT-LICENSE +1 -1
  4. data/lib/rails/application/configuration.rb +13 -4
  5. data/lib/rails/application/finisher.rb +0 -1
  6. data/lib/rails/application.rb +4 -1
  7. data/lib/rails/autoloaders/inflector.rb +1 -1
  8. data/lib/rails/autoloaders.rb +40 -36
  9. data/lib/rails/commands/dbconsole/dbconsole_command.rb +10 -7
  10. data/lib/rails/gem_version.rb +2 -2
  11. data/lib/rails/generators/actions.rb +30 -13
  12. data/lib/rails/generators/app_base.rb +77 -54
  13. data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +2 -2
  14. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +7 -2
  15. data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +1 -1
  16. data/lib/rails/generators/erb/scaffold/templates/partial.html.erb.tt +0 -3
  17. data/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt +3 -3
  18. data/lib/rails/generators/generated_attribute.rb +2 -2
  19. data/lib/rails/generators/named_base.rb +10 -10
  20. data/lib/rails/generators/rails/app/app_generator.rb +14 -0
  21. data/lib/rails/generators/rails/app/templates/Gemfile.tt +10 -14
  22. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +0 -31
  23. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +1 -1
  24. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +3 -1
  25. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt +0 -4
  26. data/lib/rails/generators/rails/plugin/plugin_generator.rb +39 -16
  27. data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +1 -1
  28. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +8 -30
  29. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +0 -5
  30. data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +5 -5
  31. data/lib/rails/generators/testing/behaviour.rb +2 -2
  32. data/lib/rails/tasks/framework.rake +5 -1
  33. data/lib/rails/templates/rails/welcome/index.html.erb +62 -49
  34. data/lib/rails.rb +1 -2
  35. metadata +17 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b284070001b693990d6b81e724e3c743a63a3cb3b2b92facb47102b72872560
4
- data.tar.gz: cb69eb78c8c0373ff652b727ef28ebefb2f25ef8f9ae1fdb0d5445378da49143
3
+ metadata.gz: 91236829ff0618a329d5e19ed00f9dd85fd6f68d44622dab451f126763faec2e
4
+ data.tar.gz: 9e7cac33fc86a0b6baf555fb4a002a31657b2d37455d9ef40efc425c042ce45e
5
5
  SHA512:
6
- metadata.gz: af3ace6e641e5dd20232ccc7eb83e9104ed40c4d85ba4f62d2f0b8d5b96f9b1fee8a31379f41145cad1ffe5aef8acf34daef558104cf13b955555e70cac19b79
7
- data.tar.gz: dee8812ce8c27baef9cb88a64c0709153096671a55d046567dd1b760ba942b1e205c3d3e8ac182b4b5628bcf2ea5448643282ac0cd080898d3b68def142dc643
6
+ metadata.gz: dc0ec824e43c9f015cd5e86d6f4754c8724ca4e61a8856b8421b9b7dbf943398dff56095bf9b646f282a423b41c71fa42f30a5d587d945b6b382c1fdd49aae31
7
+ data.tar.gz: 5725c5241ec2efd5c4a3d826df6b5548c373f6225dd144472167c08421b7350b34fca209661a174a580fb812ee85c365cdeb66b00b5747d7828a9bb85de0d584
data/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
+ ## Rails 7.0.2 (February 08, 2022) ##
2
+
3
+ * No changes.
4
+
5
+
6
+ ## Rails 7.0.1 (January 06, 2022) ##
7
+
8
+ * Prevent duplicate entries in plugin Gemfile.
9
+
10
+ *Jonathan Hefner*
11
+
12
+ * Fix asset pipeline errors for plugin dummy apps.
13
+
14
+ *Jonathan Hefner*
15
+
16
+ * Fix generated route revocation.
17
+
18
+ *Jonathan Hefner*
19
+
20
+ * Addresses an issue in which Sidekiq jobs could not reload certain
21
+ namespaces.
22
+
23
+ See [fxn/zeitwerk#198](https://github.com/fxn/zeitwerk/issues/198) for
24
+ details.
25
+
26
+ *Xavier Noria*
27
+
28
+ * Fix plugin generator to a plugin that pass all the tests.
29
+
30
+ *Rafael Mendonça França*
31
+
32
+
33
+ ## Rails 7.0.0 (December 15, 2021) ##
34
+
35
+ * No changes.
36
+
37
+
38
+ ## Rails 7.0.0.rc3 (December 14, 2021) ##
39
+
40
+ * Allow localhost with a port by default in development
41
+
42
+ [Fixes: #43864]
43
+
1
44
  ## Rails 7.0.0.rc2 (December 14, 2021) ##
2
45
 
46
+ * No changes
47
+
48
+ ## Rails 7.0.0.rc1 (December 06, 2021) ##
49
+
3
50
  * Remove deprecated `config` in `dbconsole`.
4
51
 
5
52
  *Rafael Mendonça França*
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2021 David Heinemeier Hansson
1
+ Copyright (c) 2004-2022 David Heinemeier Hansson
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
@@ -33,8 +33,12 @@ module Rails
33
33
  @filter_parameters = []
34
34
  @filter_redirect = []
35
35
  @helpers_paths = []
36
- @hosts = Array(([".localhost", IPAddr.new("0.0.0.0/0"), IPAddr.new("::/0")] if Rails.env.development?))
37
- @hosts.concat(ENV["RAILS_DEVELOPMENT_HOSTS"].to_s.split(",").map(&:strip)) if Rails.env.development?
36
+ if Rails.env.development?
37
+ @hosts = ActionDispatch::HostAuthorization::ALLOWED_HOSTS_IN_DEVELOPMENT +
38
+ ENV["RAILS_DEVELOPMENT_HOSTS"].to_s.split(",").map(&:strip)
39
+ else
40
+ @hosts = []
41
+ end
38
42
  @host_authorization = {}
39
43
  @public_file_server = ActiveSupport::OrderedOptions.new
40
44
  @public_file_server.enabled = true
@@ -77,13 +81,17 @@ module Rails
77
81
  @server_timing = false
78
82
  end
79
83
 
80
- # Loads default configurations. See {the result of the method for each version}[https://guides.rubyonrails.org/configuring.html#results-of-config-load-defaults].
84
+ # Loads default configuration values for a target version. This includes
85
+ # defaults for versions prior to the target version. See the
86
+ # {configuration guide}[https://guides.rubyonrails.org/configuring.html]
87
+ # for the default values associated with a particular version.
81
88
  def load_defaults(target_version)
82
89
  case target_version.to_s
83
90
  when "5.0"
84
91
  if respond_to?(:action_controller)
85
92
  action_controller.per_form_csrf_tokens = true
86
93
  action_controller.forgery_protection_origin_check = true
94
+ action_controller.urlsafe_csrf_tokens = false
87
95
  end
88
96
 
89
97
  ActiveSupport.to_time_preserves_timezone = true
@@ -169,7 +177,7 @@ module Rails
169
177
  end
170
178
 
171
179
  if respond_to?(:action_controller)
172
- action_controller.urlsafe_csrf_tokens = true
180
+ action_controller.delete(:urlsafe_csrf_tokens)
173
181
  end
174
182
 
175
183
  if respond_to?(:action_view)
@@ -236,6 +244,7 @@ module Rails
236
244
  " -frames:v 1 -f image2"
237
245
 
238
246
  active_storage.variant_processor = :vips
247
+ active_storage.multiple_file_field_include_hidden = true
239
248
  end
240
249
 
241
250
  if respond_to?(:active_record)
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "zeitwerk"
4
3
  require "active_support/core_ext/string/inflections"
5
4
  require "active_support/core_ext/array/conversions"
6
5
  require "active_support/descendants_tracker"
@@ -10,6 +10,7 @@ require "active_support/hash_with_indifferent_access"
10
10
  require "active_support/configuration_file"
11
11
  require "rails/engine"
12
12
  require "rails/secrets"
13
+ require "rails/autoloaders"
13
14
 
14
15
  module Rails
15
16
  # An Engine with the responsibility of coordinating the whole boot process.
@@ -95,7 +96,7 @@ module Rails
95
96
 
96
97
  attr_accessor :assets, :sandbox
97
98
  alias_method :sandbox?, :sandbox
98
- attr_reader :reloaders, :reloader, :executor
99
+ attr_reader :reloaders, :reloader, :executor, :autoloaders
99
100
 
100
101
  delegate :default_url_options, :default_url_options=, to: :routes
101
102
 
@@ -117,6 +118,8 @@ module Rails
117
118
  @reloader = Class.new(ActiveSupport::Reloader)
118
119
  @reloader.executor = @executor
119
120
 
121
+ @autoloaders = Rails::Autoloaders.new
122
+
120
123
  # are these actually used?
121
124
  @initial_variable_values = initial_variable_values
122
125
  @block = block
@@ -3,7 +3,7 @@
3
3
  require "active_support/inflector"
4
4
 
5
5
  module Rails
6
- module Autoloaders
6
+ class Autoloaders
7
7
  module Inflector # :nodoc:
8
8
  # Concurrent::Map is not needed. This is a private class, and overrides
9
9
  # must be defined while the application boots.
@@ -1,44 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "zeitwerk"
4
-
5
3
  module Rails
6
- module Autoloaders # :nodoc:
4
+ class Autoloaders # :nodoc:
7
5
  require_relative "autoloaders/inflector"
8
6
 
9
- class << self
10
- include Enumerable
11
-
12
- def main
13
- @main ||= Zeitwerk::Loader.new.tap do |loader|
14
- loader.tag = "rails.main"
15
- loader.inflector = Inflector
16
- end
17
- end
18
-
19
- def once
20
- @once ||= Zeitwerk::Loader.new.tap do |loader|
21
- loader.tag = "rails.once"
22
- loader.inflector = Inflector
23
- end
24
- end
25
-
26
- def each
27
- yield main
28
- yield once
29
- end
30
-
31
- def logger=(logger)
32
- each { |loader| loader.logger = logger }
33
- end
34
-
35
- def log!
36
- each(&:log!)
37
- end
38
-
39
- def zeitwerk_enabled?
40
- true
41
- end
7
+ include Enumerable
8
+
9
+ attr_reader :main, :once
10
+
11
+ def initialize
12
+ # This `require` delays loading the library on purpose.
13
+ #
14
+ # In Rails 7.0.0, railties/lib/rails.rb loaded Zeitwerk as a side-effect,
15
+ # but a couple of edge cases related to Bundler and Bootsnap showed up.
16
+ # They had to do with order of decoration of `Kernel#require`, something
17
+ # the three of them do.
18
+ #
19
+ # Delaying this `require` up to this point is a convenient trade-off.
20
+ require "zeitwerk"
21
+
22
+ @main = Zeitwerk::Loader.new
23
+ @main.tag = "rails.main"
24
+ @main.inflector = Inflector
25
+
26
+ @once = Zeitwerk::Loader.new
27
+ @once.tag = "rails.once"
28
+ @once.inflector = Inflector
29
+ end
30
+
31
+ def each
32
+ yield main
33
+ yield once
34
+ end
35
+
36
+ def logger=(logger)
37
+ each { |loader| loader.logger = logger }
38
+ end
39
+
40
+ def log!
41
+ each(&:log!)
42
+ end
43
+
44
+ def zeitwerk_enabled?
45
+ true
42
46
  end
43
47
  end
44
48
  end
@@ -97,15 +97,18 @@ module Rails
97
97
  def db_config
98
98
  return @db_config if defined?(@db_config)
99
99
 
100
- # We need to check whether the user passed the database the
101
- # first time around to show a consistent error message to people
102
- # relying on 2-level database configuration.
103
-
104
- @db_config = configurations.configs_for(env_name: environment, name: database, include_hidden: true)
100
+ # If the user provided a database, use that. Otherwise find
101
+ # the first config in the database.yml
102
+ if database
103
+ @db_config = configurations.configs_for(env_name: environment, name: database, include_hidden: true)
104
+ else
105
+ @db_config = configurations.find_db_config(environment)
106
+ end
105
107
 
106
108
  unless @db_config
109
+ missing_db = database ? "'#{database}' database is not" : "No databases are"
107
110
  raise ActiveRecord::AdapterNotSpecified,
108
- "'#{database}' database is not configured for '#{environment}'. Available configuration: #{configurations.inspect}"
111
+ "#{missing_db} configured for '#{environment}'. Available configuration: #{configurations.inspect}"
109
112
  end
110
113
 
111
114
  @db_config
@@ -116,7 +119,7 @@ module Rails
116
119
  end
117
120
 
118
121
  def database
119
- @options.fetch(:database, "primary")
122
+ @options[:database]
120
123
  end
121
124
 
122
125
  private
@@ -9,8 +9,8 @@ module Rails
9
9
  module VERSION
10
10
  MAJOR = 7
11
11
  MINOR = 0
12
- TINY = 0
13
- PRE = "rc2"
12
+ TINY = 2
13
+ PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -279,26 +279,32 @@ module Rails
279
279
  # route "root 'welcome#index'"
280
280
  # route "root 'admin#index'", namespace: :admin
281
281
  def route(routing_code, namespace: nil)
282
- routing_code = Array(namespace).reverse.reduce(routing_code) do |code, ns|
283
- "namespace :#{ns} do\n#{optimize_indentation(code, 2)}end"
282
+ namespace = Array(namespace)
283
+ namespace_pattern = route_namespace_pattern(namespace)
284
+ routing_code = namespace.reverse.reduce(routing_code) do |code, name|
285
+ "namespace :#{name} do\n#{rebase_indentation(code, 2)}end"
284
286
  end
285
287
 
286
288
  log :route, routing_code
287
289
 
288
- after_pattern = Array(namespace).each_with_index.reverse_each.reduce(nil) do |pattern, (ns, i)|
289
- margin = "\\#{i + 1}[ ]{2}"
290
- "(?:(?:^[ ]*\n|^#{margin}.*\n)*?^(#{margin})namespace :#{ns} do\n#{pattern})?"
291
- end.then do |pattern|
292
- /^([ ]*).+\.routes\.draw do[ ]*\n#{pattern}/
293
- end
294
-
295
290
  in_root do
296
- if existing = match_file("config/routes.rb", after_pattern)
297
- base_indent, *, prev_indent = existing.captures.compact.map(&:length)
298
- routing_code = optimize_indentation(routing_code, base_indent + 2).lines.grep_v(/^[ ]{,#{prev_indent}}\S/).join
291
+ if namespace_match = match_file("config/routes.rb", namespace_pattern)
292
+ base_indent, *, existing_block_indent = namespace_match.captures.compact.map(&:length)
293
+ existing_line_pattern = /^[ ]{,#{existing_block_indent}}\S.+\n?/
294
+ routing_code = rebase_indentation(routing_code, base_indent + 2).gsub(existing_line_pattern, "")
295
+ namespace_pattern = /#{Regexp.escape namespace_match.to_s}/
299
296
  end
300
297
 
301
- inject_into_file "config/routes.rb", routing_code, after: after_pattern, verbose: false, force: false
298
+ inject_into_file "config/routes.rb", routing_code, after: namespace_pattern, verbose: false, force: false
299
+
300
+ if behavior == :revoke && namespace.any? && namespace_match
301
+ empty_block_pattern = /(#{namespace_pattern})((?:\s*end\n){1,#{namespace.size}})/
302
+ gsub_file "config/routes.rb", empty_block_pattern, verbose: false, force: true do |matched|
303
+ beginning, ending = empty_block_pattern.match(matched).captures
304
+ ending.sub!(/\A\s*end\n/, "") while !ending.empty? && beginning.sub!(/^[ ]*namespace .+ do\n\s*\z/, "")
305
+ beginning + ending
306
+ end
307
+ end
302
308
  end
303
309
  end
304
310
 
@@ -363,6 +369,7 @@ module Rails
363
369
  return "#{value}\n" unless value.is_a?(String)
364
370
  "#{value.strip_heredoc.indent(amount).chomp}\n"
365
371
  end
372
+ alias rebase_indentation optimize_indentation
366
373
 
367
374
  # Indent the +Gemfile+ to the depth of @indentation
368
375
  def indentation # :doc:
@@ -387,6 +394,16 @@ module Rails
387
394
  def match_file(path, pattern)
388
395
  File.read(path).match(pattern) if File.exist?(path)
389
396
  end
397
+
398
+ def route_namespace_pattern(namespace)
399
+ namespace.each_with_index.reverse_each.reduce(nil) do |pattern, (name, i)|
400
+ cummulative_margin = "\\#{i + 1}[ ]{2}"
401
+ blank_or_indented_line = "^[ ]*\n|^#{cummulative_margin}.*\n"
402
+ "(?:(?:#{blank_or_indented_line})*?^(#{cummulative_margin})namespace :#{name} do\n#{pattern})?"
403
+ end.then do |pattern|
404
+ /^([ ]*).+\.routes\.draw do[ ]*\n#{pattern}/
405
+ end
406
+ end
390
407
  end
391
408
  end
392
409
  end
@@ -100,23 +100,26 @@ module Rails
100
100
  desc: "Show this help message and quit"
101
101
  end
102
102
 
103
- def initialize(*)
103
+ def initialize(positional_argv, option_argv, *)
104
+ @argv = [*positional_argv, *option_argv]
104
105
  @gem_filter = lambda { |gem| true }
105
106
  super
106
107
  end
107
108
 
108
109
  private
109
110
  def gemfile_entries # :doc:
110
- [rails_gemfile_entry,
111
- asset_pipeline_gemfile_entry,
112
- database_gemfile_entry,
113
- web_server_gemfile_entry,
114
- javascript_gemfile_entry,
115
- hotwire_gemfile_entry,
116
- css_gemfile_entry,
117
- jbuilder_gemfile_entry,
118
- psych_gemfile_entry,
119
- cable_gemfile_entry].flatten.find_all(&@gem_filter)
111
+ [
112
+ rails_gemfile_entry,
113
+ asset_pipeline_gemfile_entry,
114
+ database_gemfile_entry,
115
+ web_server_gemfile_entry,
116
+ javascript_gemfile_entry,
117
+ hotwire_gemfile_entry,
118
+ css_gemfile_entry,
119
+ jbuilder_gemfile_entry,
120
+ psych_gemfile_entry,
121
+ cable_gemfile_entry,
122
+ ].flatten.compact.select(&@gem_filter)
120
123
  end
121
124
 
122
125
  def builder # :doc:
@@ -158,7 +161,8 @@ module Rails
158
161
  end
159
162
 
160
163
  def database_gemfile_entry # :doc:
161
- return [] if options[:skip_active_record]
164
+ return if options[:skip_active_record]
165
+
162
166
  gem_name, gem_version = gem_for_database
163
167
  GemfileEntry.version gem_name, gem_version,
164
168
  "Use #{options[:database]} as the database for Active Record"
@@ -169,15 +173,13 @@ module Rails
169
173
  end
170
174
 
171
175
  def asset_pipeline_gemfile_entry
172
- return [] if options[:skip_asset_pipeline]
176
+ return if options[:skip_asset_pipeline]
173
177
 
174
178
  if options[:asset_pipeline] == "sprockets"
175
- GemfileEntry.version "sprockets-rails", ">= 3.4.1",
179
+ GemfileEntry.floats "sprockets-rails",
176
180
  "The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]"
177
181
  elsif options[:asset_pipeline] == "propshaft"
178
- GemfileEntry.version "propshaft", ">= 0.4.1", "The modern asset pipeline for Rails [https://github.com/rails/propshaft/]"
179
- else
180
- []
182
+ GemfileEntry.floats "propshaft", "The modern asset pipeline for Rails [https://github.com/rails/propshaft]"
181
183
  end
182
184
  end
183
185
 
@@ -255,39 +257,40 @@ module Rails
255
257
  new(name, version, comment)
256
258
  end
257
259
 
260
+ def self.floats(name, comment = nil)
261
+ new(name, nil, comment)
262
+ end
263
+
258
264
  def self.path(name, path, comment = nil)
259
265
  new(name, nil, comment, path: path)
260
266
  end
261
267
 
262
- def version
263
- version = super
264
-
265
- if version.is_a?(Array)
266
- version.join('", "')
267
- else
268
- version
269
- end
268
+ def to_s
269
+ [
270
+ (comment.gsub(/^/, "# ").chomp + "\n" if comment),
271
+ ("# " if commented_out),
272
+ "gem \"#{name}\"",
273
+ *Array(version).map { |constraint| ", \"#{constraint}\"" },
274
+ *options.map { |key, value| ", #{key}: #{value.inspect}" },
275
+ ].compact.join
270
276
  end
271
277
  end
272
278
 
279
+ def rails_prerelease?
280
+ options.dev? || options.edge? || options.main?
281
+ end
282
+
273
283
  def rails_gemfile_entry
274
284
  if options.dev?
275
- [
276
- GemfileEntry.path("rails", Rails::Generators::RAILS_DEV_PATH, "Use local checkout of Rails")
277
- ]
285
+ GemfileEntry.path("rails", Rails::Generators::RAILS_DEV_PATH, "Use local checkout of Rails")
278
286
  elsif options.edge?
279
287
  edge_branch = Rails.gem_version.prerelease? ? "main" : [*Rails.gem_version.segments.first(2), "stable"].join("-")
280
- [
281
- GemfileEntry.github("rails", "rails/rails", edge_branch, "Use specific branch of Rails")
282
- ]
288
+ GemfileEntry.github("rails", "rails/rails", edge_branch, "Use specific branch of Rails")
283
289
  elsif options.main?
284
- [
285
- GemfileEntry.github("rails", "rails/rails", "main", "Use main development branch of Rails")
286
- ]
290
+ GemfileEntry.github("rails", "rails/rails", "main", "Use main development branch of Rails")
287
291
  else
288
- [GemfileEntry.version("rails",
289
- rails_version_specifier,
290
- %(Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"))]
292
+ GemfileEntry.version("rails", rails_version_specifier,
293
+ %(Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"))
291
294
  end
292
295
  end
293
296
 
@@ -305,29 +308,28 @@ module Rails
305
308
  end
306
309
 
307
310
  def jbuilder_gemfile_entry
308
- return [] if options[:skip_jbuilder]
309
- comment = "Build JSON APIs with ease [https://github.com/rails/jbuilder]"
310
- GemfileEntry.new "jbuilder", "~> 2.11", comment, {}, options[:api]
311
+ return if options[:skip_jbuilder]
312
+ GemfileEntry.new "jbuilder", nil, "Build JSON APIs with ease [https://github.com/rails/jbuilder]", {}, options[:api]
311
313
  end
312
314
 
313
315
  def javascript_gemfile_entry
314
- return [] if options[:skip_javascript]
316
+ return if options[:skip_javascript]
315
317
 
316
318
  if adjusted_javascript_option == "importmap"
317
- GemfileEntry.version("importmap-rails", ">= 0.9.2", "Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]")
319
+ GemfileEntry.floats "importmap-rails", "Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]"
318
320
  else
319
- GemfileEntry.version "jsbundling-rails", ">= 0.2.2", "Bundle and transpile JavaScript [https://github.com/rails/jsbundling-rails]"
321
+ GemfileEntry.floats "jsbundling-rails", "Bundle and transpile JavaScript [https://github.com/rails/jsbundling-rails]"
320
322
  end
321
323
  end
322
324
 
323
325
  def hotwire_gemfile_entry
324
- return [] if options[:skip_javascript] || options[:skip_hotwire]
326
+ return if options[:skip_javascript] || options[:skip_hotwire]
325
327
 
326
328
  turbo_rails_entry =
327
- GemfileEntry.version("turbo-rails", ">= 0.9.0", "Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]")
329
+ GemfileEntry.floats "turbo-rails", "Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]"
328
330
 
329
331
  stimulus_rails_entry =
330
- GemfileEntry.version("stimulus-rails", ">= 0.7.3", "Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]")
332
+ GemfileEntry.floats "stimulus-rails", "Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]"
331
333
 
332
334
  [ turbo_rails_entry, stimulus_rails_entry ]
333
335
  end
@@ -347,17 +349,17 @@ module Rails
347
349
  end
348
350
 
349
351
  def css_gemfile_entry
350
- return [] unless options[:css]
352
+ return unless options[:css]
351
353
 
352
354
  if !using_node? && options[:css] == "tailwind"
353
- GemfileEntry.version("tailwindcss-rails", ">= 0.5.3", "Use Tailwind CSS [https://github.com/rails/tailwindcss-rails]")
355
+ GemfileEntry.floats "tailwindcss-rails", "Use Tailwind CSS [https://github.com/rails/tailwindcss-rails]"
354
356
  else
355
- GemfileEntry.version("cssbundling-rails", ">= 0.2.7", "Bundle and process CSS [https://github.com/rails/cssbundling-rails]")
357
+ GemfileEntry.floats "cssbundling-rails", "Bundle and process CSS [https://github.com/rails/cssbundling-rails]"
356
358
  end
357
359
  end
358
360
 
359
361
  def psych_gemfile_entry
360
- return [] unless defined?(Rubinius)
362
+ return unless defined?(Rubinius)
361
363
 
362
364
  comment = "Use Psych as the YAML engine, instead of Syck, so serialized " \
363
365
  "data can be read safely from different rubies (see http://git.io/uuLVag)"
@@ -365,11 +367,10 @@ module Rails
365
367
  end
366
368
 
367
369
  def cable_gemfile_entry
368
- return [] if options[:skip_action_cable]
370
+ return if options[:skip_action_cable]
371
+
369
372
  comment = "Use Redis adapter to run Action Cable in production"
370
- gems = []
371
- gems << GemfileEntry.new("redis", "~> 4.0", comment, {}, true)
372
- gems
373
+ GemfileEntry.new("redis", "~> 4.0", comment, {}, true)
373
374
  end
374
375
 
375
376
  def bundle_command(command, env = {})
@@ -410,6 +411,28 @@ module Rails
410
411
  !options[:skip_bootsnap] && !options[:dev] && !defined?(JRUBY_VERSION)
411
412
  end
412
413
 
414
+ def target_rails_prerelease(self_command = "new")
415
+ return unless rails_prerelease? && bundle_install?
416
+
417
+ if !File.exist?(File.expand_path("Gemfile", destination_root))
418
+ create_file("Gemfile", <<~GEMFILE)
419
+ source "https://rubygems.org"
420
+ git_source(:github) { |repo| "https://github.com/\#{repo}.git" }
421
+ #{rails_gemfile_entry}
422
+ GEMFILE
423
+
424
+ run_bundle
425
+
426
+ @argv[0] = destination_root
427
+ require "shellwords"
428
+ bundle_command("exec rails #{self_command} #{Shellwords.join(@argv)}")
429
+ exit
430
+ else
431
+ remove_file("Gemfile")
432
+ remove_file("Gemfile.lock")
433
+ end
434
+ end
435
+
413
436
  def run_bundle
414
437
  bundle_command("install", "BUNDLE_IGNORE_MESSAGES" => "1") if bundle_install?
415
438
  end
@@ -5,6 +5,6 @@
5
5
  <br>
6
6
 
7
7
  <div>
8
- <%%= link_to "Show this <%= human_name.downcase %>", @<%= singular_table_name %> %> |
9
- <%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper %>_path %>
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
10
  </div>
@@ -3,7 +3,12 @@
3
3
  <h1><%= human_name.pluralize %></h1>
4
4
 
5
5
  <div id="<%= plural_table_name %>">
6
- <%%= render @<%= 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 %>
7
12
  </div>
8
13
 
9
- <%%= link_to "New <%= human_name.downcase %>", new_<%= singular_route_name %>_path %>
14
+ <%%= link_to "New <%= human_name.downcase %>", <%= new_helper(type: :path) %> %>
@@ -5,5 +5,5 @@
5
5
  <br>
6
6
 
7
7
  <div>
8
- <%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper %>_path %>
8
+ <%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper(type: :path) %> %>
9
9
  </div>
@@ -14,7 +14,4 @@
14
14
  </p>
15
15
 
16
16
  <% end -%>
17
- <p>
18
- <%%= link_to "Show this <%= human_name.downcase %>", <%= singular_name %> %>
19
- </p>
20
17
  </div>
@@ -3,8 +3,8 @@
3
3
  <%%= render @<%= singular_table_name %> %>
4
4
 
5
5
  <div>
6
- <%%= link_to "Edit this <%= human_name.downcase %>", edit_<%= singular_table_name %>_path(@<%= singular_table_name %>) %> |
7
- <%%= link_to "Back to <%= human_name.pluralize.downcase %>", <%= index_helper %>_path %>
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
8
 
9
- <%%= button_to "Destroy this <%= human_name.downcase %>", <%= singular_table_name %>_path(@<%= singular_table_name %>), method: :delete %>
9
+ <%%= button_to "Destroy this <%= human_name.downcase %>", <%= model_resource_name(prefix: "@") %>, method: :delete %>
10
10
  </div>