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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +72 -219
- data/README.rdoc +1 -1
- data/lib/minitest/rails_plugin.rb +48 -12
- data/lib/rails/application/bootstrap.rb +6 -3
- data/lib/rails/application/configuration.rb +26 -0
- data/lib/rails/application/default_middleware_stack.rb +1 -1
- data/lib/rails/application/finisher.rb +2 -1
- data/lib/rails/application/routes_reloader.rb +1 -2
- data/lib/rails/application.rb +6 -4
- data/lib/rails/application_controller.rb +2 -0
- data/lib/rails/command/base.rb +0 -2
- data/lib/rails/command/environment_argument.rb +0 -1
- data/lib/rails/command.rb +1 -1
- data/lib/rails/commands/console/irb_console.rb +6 -5
- data/lib/rails/commands/credentials/credentials_command.rb +25 -5
- data/lib/rails/commands/encrypted/encrypted_command.rb +0 -1
- data/lib/rails/engine/lazy_route_set.rb +8 -11
- data/lib/rails/engine.rb +0 -1
- data/lib/rails/gem_version.rb +3 -3
- data/lib/rails/generators/actions.rb +2 -3
- data/lib/rails/generators/app_base.rb +43 -54
- data/lib/rails/generators/bundle_helper.rb +34 -0
- data/lib/rails/generators/database.rb +1 -1
- data/lib/rails/generators/erb/authentication/authentication_generator.rb +2 -0
- data/lib/rails/generators/erb/scaffold/templates/partial.html.erb.tt +2 -2
- data/lib/rails/generators/generated_attribute.rb +1 -1
- data/lib/rails/generators/migration.rb +0 -1
- data/lib/rails/generators/rails/app/app_generator.rb +14 -4
- data/lib/rails/generators/rails/app/templates/Dockerfile.tt +15 -13
- data/lib/rails/generators/rails/app/templates/Gemfile.tt +3 -0
- data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +5 -0
- data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +1 -0
- data/lib/rails/generators/rails/app/templates/bin/bundler-audit.tt +5 -0
- data/lib/rails/generators/rails/app/templates/bin/ci.tt +5 -0
- data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +1 -1
- data/lib/rails/generators/rails/app/templates/bin/setup.tt +1 -0
- data/lib/rails/generators/rails/app/templates/config/bundler-audit.yml.tt +5 -0
- data/lib/rails/generators/rails/app/templates/config/ci.rb.tt +34 -0
- data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +9 -1
- data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +10 -2
- data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +9 -1
- data/lib/rails/generators/rails/app/templates/config/deploy.yml.tt +5 -5
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +5 -0
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +16 -4
- data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +4 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_1.rb.tt +66 -0
- data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +3 -2
- data/lib/rails/generators/rails/app/templates/config/storage.yml.tt +0 -7
- data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +0 -6
- data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +101 -19
- data/lib/rails/generators/rails/app/templates/github/dependabot.yml +2 -2
- data/lib/rails/generators/rails/app/templates/kamal-secrets.tt +3 -0
- data/lib/rails/generators/rails/app/templates/public/400.html +1 -1
- data/lib/rails/generators/rails/app/templates/public/404.html +2 -2
- data/lib/rails/generators/rails/app/templates/public/422.html +1 -1
- data/lib/rails/generators/rails/app/templates/public/500.html +2 -2
- data/lib/rails/generators/rails/authentication/authentication_generator.rb +22 -9
- data/lib/rails/generators/rails/authentication/templates/app/controllers/passwords_controller.rb.tt +6 -0
- data/lib/rails/generators/rails/authentication/templates/app/controllers/sessions_controller.rb.tt +2 -2
- data/lib/rails/generators/rails/authentication/templates/test/test_helpers/session_test_helper.rb.tt +15 -0
- data/lib/rails/generators/rails/benchmark/USAGE +1 -1
- data/lib/rails/generators/rails/benchmark/templates/benchmark.rb.tt +0 -2
- data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +4 -0
- data/lib/rails/generators/rails/devcontainer/templates/devcontainer/compose.yaml.tt +2 -2
- data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +17 -5
- data/lib/rails/generators/rails/master_key/master_key_generator.rb +0 -12
- data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +20 -9
- data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +2 -2
- data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +2 -2
- data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +2 -2
- data/lib/rails/generators/rails/script/USAGE +1 -1
- data/lib/rails/generators/test_unit/authentication/authentication_generator.rb +5 -0
- data/lib/rails/generators/test_unit/authentication/templates/test/controllers/passwords_controller_test.rb.tt +67 -0
- data/lib/rails/generators/test_unit/authentication/templates/test/controllers/sessions_controller_test.rb +33 -0
- data/lib/rails/generators/test_unit/authentication/templates/test/models/user_test.rb.tt +4 -3
- data/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt +1 -1
- data/lib/rails/generators/testing/behavior.rb +0 -3
- data/lib/rails/generators.rb +3 -1
- data/lib/rails/health_controller.rb +10 -2
- data/lib/rails/info.rb +4 -4
- data/lib/rails/info_controller.rb +2 -3
- data/lib/rails/initializable.rb +63 -19
- data/lib/rails/rack/silence_request.rb +5 -2
- data/lib/rails/railtie/configurable.rb +0 -1
- data/lib/rails/railtie.rb +0 -1
- data/lib/rails/templates/rails/info/notes.html.erb +23 -0
- data/lib/rails/templates/rails/mailers/email.html.erb +2 -1
- data/lib/rails/templates/rails/welcome/index.html.erb +17 -1
- data/lib/rails/test_unit/reporter.rb +5 -4
- data/lib/rails/test_unit/runner.rb +8 -5
- data/lib/rails.rb +9 -2
- metadata +35 -16
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_0.rb.tt +0 -30
- data/lib/rails/generators/test_unit/plugin/plugin_generator.rb +0 -15
- data/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt +0 -7
- 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
|
-
|
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 ||
|
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
|
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
|
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
data/lib/rails/gem_version.rb
CHANGED
@@ -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+.
|
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
|
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
|
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[:
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
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] && !
|
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
|
766
|
-
|
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 ||=
|
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
|
-
|
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
|
@@ -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
|
-
<
|
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
|
-
</
|
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.
|
76
|
+
ActiveRecord::Base.connection_db_config.adapter_class.valid_type?(type)
|
77
77
|
end
|
78
78
|
|
79
79
|
def valid_index_type?(index_type)
|
@@ -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.
|
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 %>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "bundler/setup"
|
3
3
|
|
4
|
-
#
|
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")
|