railties 8.0.2 → 8.1.0.beta1

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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -219
  3. data/README.rdoc +1 -1
  4. data/lib/minitest/rails_plugin.rb +48 -12
  5. data/lib/rails/application/bootstrap.rb +6 -3
  6. data/lib/rails/application/configuration.rb +26 -0
  7. data/lib/rails/application/default_middleware_stack.rb +1 -1
  8. data/lib/rails/application/finisher.rb +2 -1
  9. data/lib/rails/application/routes_reloader.rb +1 -2
  10. data/lib/rails/application.rb +6 -4
  11. data/lib/rails/application_controller.rb +2 -0
  12. data/lib/rails/command/base.rb +0 -2
  13. data/lib/rails/command/environment_argument.rb +0 -1
  14. data/lib/rails/command.rb +1 -1
  15. data/lib/rails/commands/console/irb_console.rb +6 -5
  16. data/lib/rails/commands/credentials/credentials_command.rb +25 -5
  17. data/lib/rails/commands/encrypted/encrypted_command.rb +0 -1
  18. data/lib/rails/engine/lazy_route_set.rb +8 -11
  19. data/lib/rails/engine.rb +0 -1
  20. data/lib/rails/gem_version.rb +3 -3
  21. data/lib/rails/generators/actions.rb +2 -3
  22. data/lib/rails/generators/app_base.rb +43 -54
  23. data/lib/rails/generators/bundle_helper.rb +34 -0
  24. data/lib/rails/generators/database.rb +1 -1
  25. data/lib/rails/generators/erb/authentication/authentication_generator.rb +2 -0
  26. data/lib/rails/generators/erb/scaffold/templates/partial.html.erb.tt +2 -2
  27. data/lib/rails/generators/generated_attribute.rb +1 -1
  28. data/lib/rails/generators/migration.rb +0 -1
  29. data/lib/rails/generators/rails/app/app_generator.rb +14 -4
  30. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +15 -13
  31. data/lib/rails/generators/rails/app/templates/Gemfile.tt +3 -0
  32. data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +5 -0
  33. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +1 -0
  34. data/lib/rails/generators/rails/app/templates/bin/bundler-audit.tt +5 -0
  35. data/lib/rails/generators/rails/app/templates/bin/ci.tt +5 -0
  36. data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +1 -1
  37. data/lib/rails/generators/rails/app/templates/bin/setup.tt +1 -0
  38. data/lib/rails/generators/rails/app/templates/config/bundler-audit.yml.tt +5 -0
  39. data/lib/rails/generators/rails/app/templates/config/ci.rb.tt +34 -0
  40. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +9 -1
  41. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +10 -2
  42. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +1 -1
  43. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +9 -1
  44. data/lib/rails/generators/rails/app/templates/config/deploy.yml.tt +5 -5
  45. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +5 -0
  46. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +16 -4
  47. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +4 -0
  48. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_1.rb.tt +66 -0
  49. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +3 -2
  50. data/lib/rails/generators/rails/app/templates/config/storage.yml.tt +0 -7
  51. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +0 -6
  52. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +101 -19
  53. data/lib/rails/generators/rails/app/templates/github/dependabot.yml +2 -2
  54. data/lib/rails/generators/rails/app/templates/kamal-secrets.tt +3 -0
  55. data/lib/rails/generators/rails/app/templates/public/400.html +1 -1
  56. data/lib/rails/generators/rails/app/templates/public/404.html +2 -2
  57. data/lib/rails/generators/rails/app/templates/public/422.html +1 -1
  58. data/lib/rails/generators/rails/app/templates/public/500.html +2 -2
  59. data/lib/rails/generators/rails/authentication/authentication_generator.rb +22 -9
  60. data/lib/rails/generators/rails/authentication/templates/app/controllers/passwords_controller.rb.tt +6 -0
  61. data/lib/rails/generators/rails/authentication/templates/app/controllers/sessions_controller.rb.tt +2 -2
  62. data/lib/rails/generators/rails/authentication/templates/test/test_helpers/session_test_helper.rb.tt +15 -0
  63. data/lib/rails/generators/rails/benchmark/USAGE +1 -1
  64. data/lib/rails/generators/rails/benchmark/templates/benchmark.rb.tt +0 -2
  65. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +4 -0
  66. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/compose.yaml.tt +2 -2
  67. data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +17 -5
  68. data/lib/rails/generators/rails/master_key/master_key_generator.rb +0 -12
  69. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +20 -9
  70. data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +2 -2
  71. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +2 -2
  72. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +2 -2
  73. data/lib/rails/generators/rails/script/USAGE +1 -1
  74. data/lib/rails/generators/test_unit/authentication/authentication_generator.rb +5 -0
  75. data/lib/rails/generators/test_unit/authentication/templates/test/controllers/passwords_controller_test.rb.tt +67 -0
  76. data/lib/rails/generators/test_unit/authentication/templates/test/controllers/sessions_controller_test.rb +33 -0
  77. data/lib/rails/generators/test_unit/authentication/templates/test/models/user_test.rb.tt +4 -3
  78. data/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt +1 -1
  79. data/lib/rails/generators/testing/behavior.rb +0 -3
  80. data/lib/rails/generators.rb +3 -1
  81. data/lib/rails/health_controller.rb +10 -2
  82. data/lib/rails/info.rb +4 -4
  83. data/lib/rails/info_controller.rb +2 -3
  84. data/lib/rails/initializable.rb +63 -19
  85. data/lib/rails/rack/silence_request.rb +5 -2
  86. data/lib/rails/railtie/configurable.rb +0 -1
  87. data/lib/rails/railtie.rb +0 -1
  88. data/lib/rails/templates/rails/info/notes.html.erb +23 -0
  89. data/lib/rails/templates/rails/mailers/email.html.erb +2 -1
  90. data/lib/rails/templates/rails/welcome/index.html.erb +17 -1
  91. data/lib/rails/test_unit/reporter.rb +5 -4
  92. data/lib/rails/test_unit/runner.rb +8 -5
  93. data/lib/rails.rb +9 -2
  94. metadata +35 -16
  95. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_0.rb.tt +0 -30
  96. data/lib/rails/generators/test_unit/plugin/plugin_generator.rb +0 -15
  97. data/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt +0 -7
  98. data/lib/rails/generators/test_unit/plugin/templates/test_helper.rb +0 -2
@@ -87,12 +87,13 @@ module Rails
87
87
 
88
88
  env = colorized_env
89
89
  prompt_prefix = "%N(#{env})"
90
- IRB.conf[:IRB_NAME] = @app.name
90
+ # Respect user's configured irb name.
91
+ IRB.conf[:IRB_NAME] = @app.name if IRB.conf[:IRB_NAME] == "irb"
91
92
 
92
93
  IRB.conf[:PROMPT][:RAILS_PROMPT] = {
93
- PROMPT_I: "#{prompt_prefix}> ",
94
- PROMPT_S: "#{prompt_prefix}%l ",
95
- PROMPT_C: "#{prompt_prefix}* ",
94
+ PROMPT_I: "#{prompt_prefix}:%03n> ",
95
+ PROMPT_S: "#{prompt_prefix}:%03n%l ",
96
+ PROMPT_C: "#{prompt_prefix}:%03n* ",
96
97
  RETURN: "=> %s\n"
97
98
  }
98
99
 
@@ -121,7 +122,7 @@ module Rails
121
122
  when "production"
122
123
  IRB::Color.colorize("prod", [:RED])
123
124
  else
124
- Rails.env
125
+ IRB::Color.colorize(Rails.env, [:MAGENTA])
125
126
  end
126
127
  end
127
128
  end
@@ -35,7 +35,7 @@ module Rails
35
35
  def show
36
36
  load_environment_config!
37
37
 
38
- say credentials.read.presence || missing_credentials_message
38
+ say credentials.read.presence || missing_credentials!
39
39
  end
40
40
 
41
41
  desc "diff", "Enroll/disenroll in decrypted diffs of credentials using git"
@@ -57,6 +57,26 @@ module Rails
57
57
  say credentials.content_path.read
58
58
  end
59
59
 
60
+ desc "fetch PATH", "Fetch a value in the decrypted credentials"
61
+ def fetch(path)
62
+ load_environment_config!
63
+
64
+ if (yaml = credentials.read)
65
+ begin
66
+ value = YAML.load(yaml)
67
+ value = path.split(".").inject(value) do |doc, key|
68
+ doc.fetch(key)
69
+ end
70
+ say value.to_s
71
+ rescue KeyError, NoMethodError
72
+ say_error "Invalid or missing credential path: #{path}"
73
+ exit 1
74
+ end
75
+ else
76
+ missing_credentials!
77
+ end
78
+ end
79
+
60
80
  private
61
81
  def config
62
82
  Rails.application.config.credentials
@@ -81,7 +101,6 @@ module Rails
81
101
 
82
102
  encryption_key_file_generator = Rails::Generators::EncryptionKeyFileGenerator.new
83
103
  encryption_key_file_generator.add_key_file(key_path)
84
- encryption_key_file_generator.ignore_key_file(key_path)
85
104
  end
86
105
 
87
106
  def ensure_credentials_have_been_added
@@ -115,12 +134,13 @@ module Rails
115
134
  say "Your application will not be able to load '#{content_path}' until the error has been fixed.", :red
116
135
  end
117
136
 
118
- def missing_credentials_message
137
+ def missing_credentials!
119
138
  if !credentials.key?
120
- "Missing '#{key_path}' to decrypt credentials. See `#{executable(:help)}`."
139
+ say_error "Missing '#{key_path}' to decrypt credentials. See `#{executable(:help)}`."
121
140
  else
122
- "File '#{content_path}' does not exist. Use `#{executable(:edit)}` to change that."
141
+ say_error "File '#{content_path}' does not exist. Use `#{executable(:edit)}` to change that."
123
142
  end
143
+ exit 1
124
144
  end
125
145
 
126
146
  def relative_path(path)
@@ -45,7 +45,6 @@ module Rails
45
45
  def ensure_encryption_key_has_been_added
46
46
  return if encrypted_configuration.key?
47
47
  encryption_key_file_generator.add_key_file(key_path)
48
- encryption_key_file_generator.ignore_key_file(key_path)
49
48
  end
50
49
 
51
50
  def ensure_encrypted_configuration_has_been_added
@@ -4,9 +4,11 @@
4
4
 
5
5
  require "action_dispatch/routing/route_set"
6
6
 
7
+ # :enddoc:
8
+
7
9
  module Rails
8
10
  class Engine
9
- class LazyRouteSet < ActionDispatch::Routing::RouteSet # :nodoc:
11
+ class LazyRouteSet < ActionDispatch::Routing::RouteSet
10
12
  class NamedRouteCollection < ActionDispatch::Routing::RouteSet::NamedRouteCollection
11
13
  def route_defined?(name)
12
14
  Rails.application&.reload_routes_unless_loaded
@@ -34,16 +36,6 @@ module Rails
34
36
  Rails.application&.reload_routes_unless_loaded
35
37
  super
36
38
  end
37
-
38
- def polymorphic_url(record_or_hash_or_array, options = {})
39
- Rails.application&.reload_routes_unless_loaded
40
- super
41
- end
42
-
43
- def polymorphic_path(record_or_hash_or_array, options = {})
44
- Rails.application&.reload_routes_unless_loaded
45
- super
46
- end
47
39
  end
48
40
 
49
41
  def initialize(config = DEFAULT_CONFIG)
@@ -68,6 +60,11 @@ module Rails
68
60
  super
69
61
  end
70
62
 
63
+ def polymorphic_mappings
64
+ Rails.application&.reload_routes_unless_loaded
65
+ super
66
+ end
67
+
71
68
  def draw(&block)
72
69
  Rails.application&.reload_routes_unless_loaded
73
70
  super
data/lib/rails/engine.rb CHANGED
@@ -3,7 +3,6 @@
3
3
  require "rails/railtie"
4
4
  require "rails/engine/railties"
5
5
  require "active_support/callbacks"
6
- require "active_support/core_ext/module/delegation"
7
6
  require "active_support/core_ext/object/try"
8
7
  require "pathname"
9
8
 
@@ -8,9 +8,9 @@ module Rails
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 8
11
- MINOR = 0
12
- TINY = 2
13
- PRE = nil
11
+ MINOR = 1
12
+ TINY = 0
13
+ PRE = "beta1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -445,11 +445,10 @@ module Rails
445
445
 
446
446
  private
447
447
  # Define log for backwards compatibility. If just one argument is sent,
448
- # invoke +say+, otherwise invoke +say_status+. Differently from +say+ and
449
- # similarly to +say_status+, this method respects the +quiet?+ option given.
448
+ # invoke +say+, otherwise invoke +say_status+.
450
449
  def log(*args) # :doc:
451
450
  if args.size == 1
452
- say args.first.to_s unless options.quiet?
451
+ say args.first.to_s
453
452
  else
454
453
  args << (behavior == :invoke ? :green : :red)
455
454
  say_status(*args)
@@ -7,12 +7,14 @@ require "open-uri"
7
7
  require "tsort"
8
8
  require "uri"
9
9
  require "rails/generators"
10
+ require "rails/generators/bundle_helper"
10
11
  require "active_support/core_ext/array/extract_options"
11
12
 
12
13
  module Rails
13
14
  module Generators
14
15
  class AppBase < Base # :nodoc:
15
16
  include AppName
17
+ include BundleHelper
16
18
 
17
19
  NODE_LTS_VERSION = "20.11.1"
18
20
  BUN_VERSION = "1.0.1"
@@ -71,7 +73,8 @@ module Rails
71
73
  class_option :skip_action_cable, type: :boolean, aliases: "-C", default: nil,
72
74
  desc: "Skip Action Cable files"
73
75
 
74
- class_option :skip_asset_pipeline, type: :boolean, aliases: "-A", default: nil
76
+ class_option :skip_asset_pipeline, type: :boolean, aliases: "-A", default: nil,
77
+ desc: "Skip the asset pipeline setup"
75
78
 
76
79
  class_option :skip_javascript, type: :boolean, aliases: ["-J", "--skip-js"], default: (true if name == "plugin"),
77
80
  desc: "Skip JavaScript files"
@@ -491,7 +494,7 @@ module Rails
491
494
  def javascript_gemfile_entry
492
495
  return if options[:skip_javascript]
493
496
 
494
- if options[:javascript] == "importmap"
497
+ if using_importmap?
495
498
  GemfileEntry.floats "importmap-rails", "Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]"
496
499
  else
497
500
  GemfileEntry.floats "jsbundling-rails", "Bundle and transpile JavaScript [https://github.com/rails/jsbundling-rails]"
@@ -510,9 +513,12 @@ module Rails
510
513
  [ turbo_rails_entry, stimulus_rails_entry ]
511
514
  end
512
515
 
516
+ def using_importmap?
517
+ !options.skip_javascript? && options[:javascript] == "importmap"
518
+ end
519
+
513
520
  def using_js_runtime?
514
- (options[:javascript] && !%w[importmap].include?(options[:javascript])) ||
515
- (options[:css] && !%w[tailwind sass].include?(options[:css]))
521
+ !options.skip_javascript? && (!using_importmap? || (options[:css] && !%w[tailwind sass].include?(options[:css])))
516
522
  end
517
523
 
518
524
  def using_node?
@@ -523,31 +529,35 @@ module Rails
523
529
  using_js_runtime? && %w[bun].include?(options[:javascript])
524
530
  end
525
531
 
532
+ def capture_command(command, pattern = nil)
533
+ output = `#{command}`
534
+ if pattern
535
+ output[pattern]
536
+ else
537
+ output
538
+ end
539
+ rescue SystemCallError
540
+ nil
541
+ end
542
+
526
543
  def node_version
527
544
  if using_node?
528
545
  ENV.fetch("NODE_VERSION") do
529
- `node --version`[/\d+\.\d+\.\d+/]
530
- rescue
531
- NODE_LTS_VERSION
546
+ capture_command("node --version", /\d+\.\d+\.\d+/) || NODE_LTS_VERSION
532
547
  end
533
548
  end
534
549
  end
535
550
 
536
551
  def dockerfile_yarn_version
537
- using_node? and `yarn --version`[/\d+\.\d+\.\d+/]
538
- rescue
539
- "latest"
552
+ capture_command("yarn --version", /\d+\.\d+\.\d+/) || "latest"
540
553
  end
541
554
 
542
555
  def yarn_through_corepack?
543
- true if dockerfile_yarn_version == "latest"
544
- dockerfile_yarn_version >= "2"
556
+ using_node? and "#{dockerfile_yarn_version}" >= "2"
545
557
  end
546
558
 
547
559
  def dockerfile_bun_version
548
- using_bun? and `bun --version`[/\d+\.\d+\.\d+/]
549
- rescue
550
- BUN_VERSION
560
+ capture_command("bun --version", /\d+\.\d+\.\d+/) || BUN_VERSION
551
561
  end
552
562
 
553
563
  def dockerfile_binfile_fixups
@@ -615,11 +625,16 @@ module Rails
615
625
  end
616
626
 
617
627
  def ci_packages
618
- if depends_on_system_test?
619
- dockerfile_build_packages << "google-chrome-stable"
620
- else
621
- dockerfile_build_packages
622
- end
628
+ dockerfile_build_packages - [
629
+ # GitHub Actions doesn't have build-essential,
630
+ # but it's a meta-packages and all its dependencies are already installed.
631
+ "build-essential",
632
+ "git",
633
+ "pkg-config",
634
+ "libyaml-dev",
635
+ "unzip",
636
+ "python-is-python3",
637
+ ]
623
638
  end
624
639
 
625
640
  def css_gemfile_entry
@@ -642,32 +657,6 @@ module Rails
642
657
  end
643
658
  end
644
659
 
645
- def bundle_command(command, env = {})
646
- say_status :run, "bundle #{command}"
647
-
648
- # We are going to shell out rather than invoking Bundler::CLI.new(command)
649
- # because `rails new` loads the Thor gem and on the other hand bundler uses
650
- # its own vendored Thor, which could be a different version. Running both
651
- # things in the same process is a recipe for a night with paracetamol.
652
- #
653
- # Thanks to James Tucker for the Gem tricks involved in this call.
654
- _bundle_command = Gem.bin_path("bundler", "bundle")
655
-
656
- require "bundler"
657
- Bundler.with_original_env do
658
- exec_bundle_command(_bundle_command, command, env)
659
- end
660
- end
661
-
662
- def exec_bundle_command(bundle_command, command, env)
663
- full_command = %Q["#{Gem.ruby}" "#{bundle_command}" #{command}]
664
- if options[:quiet]
665
- system(env, full_command, out: File::NULL)
666
- else
667
- system(env, full_command)
668
- end
669
- end
670
-
671
660
  def bundle_install?
672
661
  !(options[:skip_bundle] || options[:pretend])
673
662
  end
@@ -677,7 +666,7 @@ module Rails
677
666
  end
678
667
 
679
668
  def depend_on_bootsnap?
680
- !options[:skip_bootsnap] && !options[:dev] && !defined?(JRUBY_VERSION)
669
+ !options[:skip_bootsnap] && !options[:dev] && !jruby?
681
670
  end
682
671
 
683
672
  def target_rails_prerelease(self_command = "new")
@@ -753,7 +742,7 @@ module Rails
753
742
  end
754
743
 
755
744
  def add_bundler_platforms
756
- if bundle_install?
745
+ if bundle_install? && !jruby?
757
746
  # The vast majority of Rails apps will be deployed on `x86_64-linux`.
758
747
  bundle_command("lock --add-platform=x86_64-linux")
759
748
 
@@ -762,10 +751,8 @@ module Rails
762
751
  end
763
752
  end
764
753
 
765
- def generate_bundler_binstub
766
- if bundle_install?
767
- bundle_command("binstubs bundler")
768
- end
754
+ def jruby?
755
+ defined?(JRUBY_VERSION)
769
756
  end
770
757
 
771
758
  def empty_directory_with_keep_file(destination, config = {})
@@ -778,11 +765,13 @@ module Rails
778
765
  end
779
766
 
780
767
  def user_default_branch
781
- @user_default_branch ||= `git config init.defaultbranch`
768
+ @user_default_branch ||= capture_command("git config init.defaultbranch").strip.presence || "main"
782
769
  end
783
770
 
784
771
  def git_init_command
785
- return "git init" if user_default_branch.strip.present?
772
+ if capture_command("git config init.defaultbranch").present?
773
+ return "git init"
774
+ end
786
775
 
787
776
  git_version = `git --version`[/\d+\.\d+\.\d+/]
788
777
 
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module Generators
5
+ module BundleHelper # :nodoc:
6
+ def bundle_command(command, env = {}, params = {})
7
+ say_status :run, "bundle #{command}"
8
+
9
+ # We are going to shell out rather than invoking Bundler::CLI.new(command)
10
+ # because `rails new` loads the Thor gem and on the other hand bundler uses
11
+ # its own vendored Thor, which could be a different version. Running both
12
+ # things in the same process is a recipe for a night with paracetamol.
13
+ #
14
+ # Thanks to James Tucker for the Gem tricks involved in this call.
15
+ _bundle_command = Gem.bin_path("bundler", "bundle")
16
+
17
+ require "bundler"
18
+ Bundler.with_original_env do
19
+ exec_bundle_command(_bundle_command, command, env, params)
20
+ end
21
+ end
22
+
23
+ private
24
+ def exec_bundle_command(bundle_command, command, env, params)
25
+ full_command = %Q["#{Gem.ruby}" "#{bundle_command}" #{command}]
26
+ if options[:quiet] || params[:quiet]
27
+ system(env, full_command, out: File::NULL)
28
+ else
29
+ system(env, full_command)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -218,7 +218,7 @@ module Rails
218
218
  end
219
219
 
220
220
  def base_package
221
- nil
221
+ "default-mysql-client"
222
222
  end
223
223
 
224
224
  def build_package
@@ -5,6 +5,8 @@ require "rails/generators/erb"
5
5
  module Erb # :nodoc:
6
6
  module Generators # :nodoc:
7
7
  class AuthenticationGenerator < Rails::Generators::Base # :nodoc:
8
+ hide!
9
+
8
10
  def create_files
9
11
  template "app/views/passwords/new.html.erb"
10
12
  template "app/views/passwords/edit.html.erb"
@@ -1,6 +1,6 @@
1
1
  <div id="<%%= dom_id <%= singular_name %> %>">
2
2
  <% attributes.reject(&:password_digest?).each do |attribute| -%>
3
- <p>
3
+ <div>
4
4
  <strong><%= attribute.human_name %>:</strong>
5
5
  <% if attribute.attachment? -%>
6
6
  <%%= link_to <%= singular_name %>.<%= attribute.column_name %>.filename, <%= singular_name %>.<%= attribute.column_name %> if <%= singular_name %>.<%= attribute.column_name %>.attached? %>
@@ -11,7 +11,7 @@
11
11
  <% else -%>
12
12
  <%%= <%= singular_name %>.<%= attribute.column_name %> %>
13
13
  <% end -%>
14
- </p>
14
+ </div>
15
15
 
16
16
  <% end -%>
17
17
  </div>
@@ -73,7 +73,7 @@ module Rails
73
73
  def valid_type?(type)
74
74
  DEFAULT_TYPES.include?(type.to_s) ||
75
75
  !defined?(ActiveRecord::Base) ||
76
- ActiveRecord::Base.lease_connection.valid_type?(type)
76
+ ActiveRecord::Base.connection_db_config.adapter_class.valid_type?(type)
77
77
  end
78
78
 
79
79
  def valid_index_type?(index_type)
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/concern"
4
3
  require "rails/generators/actions/create_migration"
5
4
 
6
5
  module Rails
@@ -127,7 +127,9 @@ module Rails
127
127
  template "routes.rb" unless options[:update]
128
128
  template "application.rb"
129
129
  template "environment.rb"
130
+ template "bundler-audit.yml"
130
131
  template "cable.yml" unless options[:update] || options[:skip_action_cable]
132
+ template "ci.rb"
131
133
  template "puma.rb"
132
134
  template "storage.yml" unless options[:update] || skip_active_storage?
133
135
 
@@ -140,6 +142,8 @@ module Rails
140
142
  def config_when_updating
141
143
  action_cable_config_exist = File.exist?("config/cable.yml")
142
144
  active_storage_config_exist = File.exist?("config/storage.yml")
145
+ ci_config_exist = File.exist?("config/ci.rb")
146
+ bundle_audit_config_exist = File.exist?("config/bundler-audit.yml")
143
147
  rack_cors_config_exist = File.exist?("config/initializers/cors.rb")
144
148
  assets_config_exist = File.exist?("config/initializers/assets.rb")
145
149
  asset_app_stylesheet_exist = File.exist?("app/assets/stylesheets/application.css")
@@ -157,6 +161,10 @@ module Rails
157
161
  template "config/storage.yml"
158
162
  end
159
163
 
164
+ if !ci_config_exist
165
+ template "config/ci.rb"
166
+ end
167
+
160
168
  if skip_asset_pipeline? && !assets_config_exist
161
169
  remove_file "config/initializers/assets.rb"
162
170
  end
@@ -169,6 +177,10 @@ module Rails
169
177
  remove_file "config/initializers/cors.rb"
170
178
  end
171
179
 
180
+ if !bundle_audit_config_exist
181
+ template "config/bundler-audit.yml"
182
+ end
183
+
172
184
  if options[:api]
173
185
  unless csp_config_exist
174
186
  remove_file "config/initializers/content_security_policy.rb"
@@ -182,7 +194,6 @@ module Rails
182
194
  require "rails/generators/rails/master_key/master_key_generator"
183
195
  master_key_generator = Rails::Generators::MasterKeyGenerator.new([], quiet: options[:quiet], force: options[:force])
184
196
  master_key_generator.add_master_key_file_silently
185
- master_key_generator.ignore_master_key_file_silently
186
197
  end
187
198
 
188
199
  def credentials
@@ -272,9 +283,9 @@ module Rails
272
283
  dev: options[:dev],
273
284
  node: using_node?,
274
285
  app_name: app_name,
275
- skip_solid: options[:skip_solid]
286
+ skip_solid: options[:skip_solid],
287
+ pretend: options[:pretend]
276
288
  }
277
-
278
289
  Rails::Generators::DevcontainerGenerator.new([], devcontainer_options).invoke_all
279
290
  end
280
291
  end
@@ -570,7 +581,6 @@ module Rails
570
581
  public_task :apply_rails_template
571
582
  public_task :run_bundle
572
583
  public_task :add_bundler_platforms
573
- public_task :generate_bundler_binstub
574
584
  public_task :run_javascript
575
585
  public_task :run_hotwire
576
586
  public_task :run_css
@@ -17,18 +17,20 @@ WORKDIR /rails
17
17
  # Install base packages
18
18
  RUN apt-get update -qq && \
19
19
  apt-get install --no-install-recommends -y <%= dockerfile_base_packages.join(" ") %> && \
20
+ ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so && \
20
21
  rm -rf /var/lib/apt/lists /var/cache/apt/archives
21
22
 
22
- # Set production environment
23
+ # Set production environment variables and enable jemalloc for reduced memory usage and latency.
23
24
  ENV RAILS_ENV="production" \
24
25
  BUNDLE_DEPLOYMENT="1" \
25
26
  BUNDLE_PATH="/usr/local/bundle" \
26
- BUNDLE_WITHOUT="development"
27
+ BUNDLE_WITHOUT="development" \
28
+ LD_PRELOAD="/usr/local/lib/libjemalloc.so"
27
29
 
28
30
  # Throw-away build stage to reduce size of final image
29
31
  FROM base AS build
30
32
 
31
- # Install packages needed to build gems<%= using_node? ? " and node modules" : "" %>
33
+ # Install packages needed to build gems<%= (using_node? || using_bun?) ? " and node modules" : "" %>
32
34
  RUN apt-get update -qq && \
33
35
  apt-get install --no-install-recommends -y <%= dockerfile_build_packages.join(" ") %> && \
34
36
  rm -rf /var/lib/apt/lists /var/cache/apt/archives
@@ -59,7 +61,8 @@ RUN curl -fsSL https://bun.sh/install | bash -s -- "bun-v${BUN_VERSION}"
59
61
 
60
62
  <% end -%>
61
63
  # Install application gems
62
- COPY Gemfile Gemfile.lock ./
64
+ COPY Gemfile Gemfile.lock vendor ./
65
+
63
66
  RUN bundle install && \
64
67
  rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git<% if depend_on_bootsnap? -%> && \
65
68
  bundle exec bootsnap precompile --gemfile<% end %>
@@ -72,7 +75,7 @@ RUN yarn install --immutable
72
75
  <% end -%>
73
76
  <% if using_bun? -%>
74
77
  # Install node modules
75
- COPY package.json bun.lockb ./
78
+ COPY package.json bun.lock* ./
76
79
  RUN bun install --frozen-lockfile
77
80
 
78
81
  <% end -%>
@@ -95,23 +98,22 @@ RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
95
98
 
96
99
  <% end -%>
97
100
 
98
- <% if using_node? -%>
101
+ <% if using_node? || using_bun? -%>
99
102
  RUN rm -rf node_modules
100
103
  <% end %>
101
104
 
102
105
  # Final stage for app image
103
106
  FROM base
104
107
 
105
- # Copy built artifacts: gems, application
106
- COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
107
- COPY --from=build /rails /rails
108
-
109
108
  # Run and own only the runtime files as a non-root user for security
110
109
  RUN groupadd --system --gid 1000 rails && \
111
- useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
112
- chown -R rails:rails <%= dockerfile_chown_directories.join(" ") %>
110
+ useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash
113
111
  USER 1000:1000
114
112
 
113
+ # Copy built artifacts: gems, application
114
+ COPY --chown=rails:rails --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
115
+ COPY --chown=rails:rails --from=build /rails /rails
116
+
115
117
  # Entrypoint prepares the database.
116
118
  ENTRYPOINT ["/rails/bin/docker-entrypoint"]
117
119
 
@@ -123,4 +125,4 @@ CMD ["./bin/rails", "server"]
123
125
  # Start server via Thruster by default, this can be overwritten at runtime
124
126
  EXPOSE 80
125
127
  CMD ["./bin/thrust", "./bin/rails", "server"]
126
- <% end -%>
128
+ <% end -%>
@@ -54,6 +54,9 @@ gem "thruster", require: false
54
54
  group :development, :test do
55
55
  # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
56
56
  gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"
57
+
58
+ # Audits gems for known security defects (use config/bundler-audit.yml to ignore issues)
59
+ gem "bundler-audit", require: false
57
60
  <%- unless options.skip_brakeman? -%>
58
61
 
59
62
  # Static analysis for security vulnerabilities [https://brakemanscanner.org/]
@@ -2,5 +2,10 @@ class ApplicationController < ActionController::<%= options.api? ? "API" : "Base
2
2
  <%- unless options.api? -%>
3
3
  # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
4
4
  allow_browser versions: :modern
5
+ <%- if using_importmap? -%>
6
+
7
+ # Changes to the importmap will invalidate the etag for HTML responses
8
+ stale_when_importmap_changes
9
+ <% end -%>
5
10
  <% end -%>
6
11
  end
@@ -4,6 +4,7 @@
4
4
  <title><%%= content_for(:title) || "<%= app_name.titleize %>" %></title>
5
5
  <meta name="viewport" content="width=device-width,initial-scale=1">
6
6
  <meta name="apple-mobile-web-app-capable" content="yes">
7
+ <meta name="application-name" content="<%= app_name.titleize %>">
7
8
  <meta name="mobile-web-app-capable" content="yes">
8
9
  <%%= csrf_meta_tags %>
9
10
  <%%= csp_meta_tag %>
@@ -0,0 +1,5 @@
1
+ require_relative "../config/boot"
2
+ require "bundler/audit/cli"
3
+
4
+ ARGV.concat %w[ --config config/bundler-audit.yml ] if ARGV.empty? || ARGV.include?("check")
5
+ Bundler::Audit::CLI.start
@@ -0,0 +1,5 @@
1
+ require_relative "../config/boot"
2
+ require "active_support/continuous_integration"
3
+
4
+ CI = ActiveSupport::ContinuousIntegration
5
+ require_relative "../config/ci.rb"
@@ -1,7 +1,7 @@
1
1
  require "rubygems"
2
2
  require "bundler/setup"
3
3
 
4
- # explicit rubocop config increases performance slightly while avoiding config confusion.
4
+ # Explicit RuboCop config increases performance slightly while avoiding config confusion.
5
5
  ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__))
6
6
 
7
7
  load Gem.bin_path("rubocop", "rubocop")