railties 7.0.8 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +188 -268
- data/MIT-LICENSE +1 -1
- data/RDOC_MAIN.md +99 -0
- data/README.rdoc +4 -4
- data/lib/minitest/rails_plugin.rb +67 -1
- data/lib/rails/all.rb +1 -3
- data/lib/rails/api/task.rb +39 -6
- data/lib/rails/application/bootstrap.rb +28 -10
- data/lib/rails/application/configuration.rb +228 -72
- data/lib/rails/application/default_middleware_stack.rb +8 -2
- data/lib/rails/application/dummy_config.rb +19 -0
- data/lib/rails/application/finisher.rb +50 -33
- data/lib/rails/application.rb +110 -76
- data/lib/rails/backtrace_cleaner.rb +19 -4
- data/lib/rails/cli.rb +5 -3
- data/lib/rails/command/actions.rb +10 -12
- data/lib/rails/command/base.rb +55 -53
- data/lib/rails/command/environment_argument.rb +32 -16
- data/lib/rails/command/helpers/editor.rb +17 -12
- data/lib/rails/command.rb +84 -33
- data/lib/rails/commands/about/about_command.rb +14 -0
- data/lib/rails/commands/app/update_command.rb +93 -0
- data/lib/rails/commands/application/application_command.rb +2 -0
- data/lib/rails/commands/boot/boot_command.rb +14 -0
- data/lib/rails/commands/console/console_command.rb +11 -30
- data/lib/rails/commands/console/irb_console.rb +137 -0
- data/lib/rails/commands/credentials/USAGE +53 -55
- data/lib/rails/commands/credentials/credentials_command/diffing.rb +5 -3
- data/lib/rails/commands/credentials/credentials_command.rb +64 -70
- data/lib/rails/commands/db/system/change/change_command.rb +2 -1
- data/lib/rails/commands/dbconsole/dbconsole_command.rb +32 -131
- data/lib/rails/commands/destroy/destroy_command.rb +3 -2
- data/lib/rails/commands/dev/dev_command.rb +1 -6
- data/lib/rails/commands/devcontainer/devcontainer_command.rb +39 -0
- data/lib/rails/commands/encrypted/USAGE +15 -20
- data/lib/rails/commands/encrypted/encrypted_command.rb +46 -35
- data/lib/rails/commands/gem_help/USAGE +16 -0
- data/lib/rails/commands/gem_help/gem_help_command.rb +13 -0
- data/lib/rails/commands/generate/generate_command.rb +2 -2
- data/lib/rails/commands/help/USAGE +13 -13
- data/lib/rails/commands/help/help_command.rb +21 -2
- data/lib/rails/commands/initializers/initializers_command.rb +1 -4
- data/lib/rails/commands/middleware/middleware_command.rb +17 -0
- data/lib/rails/commands/new/new_command.rb +2 -0
- data/lib/rails/commands/notes/notes_command.rb +2 -1
- data/lib/rails/commands/plugin/plugin_command.rb +2 -0
- data/lib/rails/commands/rake/rake_command.rb +25 -22
- data/lib/rails/commands/restart/restart_command.rb +14 -0
- data/lib/rails/commands/routes/routes_command.rb +13 -1
- data/lib/rails/commands/runner/USAGE +14 -12
- data/lib/rails/commands/runner/runner_command.rb +42 -19
- data/lib/rails/commands/secret/secret_command.rb +13 -0
- data/lib/rails/commands/server/server_command.rb +37 -34
- data/lib/rails/commands/test/USAGE +14 -0
- data/lib/rails/commands/test/test_command.rb +58 -14
- data/lib/rails/commands/unused_routes/unused_routes_command.rb +75 -0
- data/lib/rails/commands/version/version_command.rb +1 -0
- data/lib/rails/configuration.rb +15 -6
- data/lib/rails/console/app.rb +5 -35
- data/lib/rails/console/helpers.rb +5 -16
- data/lib/rails/console/methods.rb +23 -0
- data/lib/rails/deprecator.rb +7 -0
- data/lib/rails/engine/configuration.rb +50 -6
- data/lib/rails/engine.rb +51 -23
- data/lib/rails/gem_version.rb +3 -3
- data/lib/rails/generators/actions.rb +6 -15
- data/lib/rails/generators/active_model.rb +28 -14
- data/lib/rails/generators/app_base.rb +382 -88
- data/lib/rails/generators/app_name.rb +3 -14
- data/lib/rails/generators/base.rb +21 -9
- data/lib/rails/generators/database.rb +231 -35
- data/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt +1 -1
- data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +2 -0
- data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +2 -0
- data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +2 -0
- data/lib/rails/generators/generated_attribute.rb +38 -1
- data/lib/rails/generators/migration.rb +4 -5
- data/lib/rails/generators/model_helpers.rb +2 -1
- data/lib/rails/generators/rails/app/USAGE +22 -6
- data/lib/rails/generators/rails/app/app_generator.rb +132 -82
- data/lib/rails/generators/rails/app/templates/Dockerfile.tt +110 -0
- data/lib/rails/generators/rails/app/templates/Gemfile.tt +19 -21
- data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +4 -0
- data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +8 -1
- data/lib/rails/generators/rails/app/templates/app/views/layouts/mailer.html.erb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/app/views/pwa/manifest.json.erb.tt +22 -0
- data/lib/rails/generators/rails/app/templates/app/views/pwa/service-worker.js +26 -0
- data/lib/rails/generators/rails/app/templates/bin/brakeman.tt +6 -0
- data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +7 -0
- data/lib/rails/generators/rails/app/templates/bin/setup.tt +15 -2
- data/lib/rails/generators/rails/app/templates/config/application.rb.tt +6 -17
- data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +3 -3
- data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +11 -6
- data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +10 -3
- data/lib/rails/generators/rails/app/templates/config/databases/{jdbcmysql.yml.tt → trilogy.yml.tt} +12 -7
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +25 -8
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +37 -28
- data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +20 -13
- data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +2 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +2 -2
- data/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +4 -4
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +70 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +11 -9
- data/lib/rails/generators/rails/app/templates/config/locales/en.yml +11 -13
- data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +24 -34
- data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +9 -1
- data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +6 -4
- data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +15 -0
- data/lib/rails/generators/rails/app/templates/dockerignore.tt +56 -0
- data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +138 -0
- data/lib/rails/generators/rails/app/templates/github/dependabot.yml +12 -0
- data/lib/rails/generators/rails/app/templates/gitignore.tt +7 -11
- data/lib/rails/generators/rails/app/templates/node-version.tt +1 -0
- data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +66 -0
- data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
- data/lib/rails/generators/rails/app/templates/public/icon.svg +3 -0
- data/lib/rails/generators/rails/app/templates/rubocop.yml.tt +8 -0
- data/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt +1 -1
- data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +10 -8
- data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +9 -7
- data/lib/rails/generators/rails/application_record/application_record_generator.rb +4 -0
- data/lib/rails/generators/rails/benchmark/benchmark_generator.rb +2 -1
- data/lib/rails/generators/rails/controller/USAGE +12 -4
- data/lib/rails/generators/rails/controller/controller_generator.rb +6 -1
- data/lib/rails/generators/rails/controller/templates/controller.rb.tt +1 -1
- data/lib/rails/generators/rails/credentials/credentials_generator.rb +29 -24
- data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +8 -0
- data/lib/rails/generators/rails/db/system/change/change_generator.rb +146 -5
- data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +166 -0
- data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +3 -0
- data/lib/rails/generators/rails/devcontainer/templates/devcontainer/compose.yaml.tt +47 -0
- data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +37 -0
- data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +1 -2
- data/lib/rails/generators/rails/migration/USAGE +21 -11
- data/lib/rails/generators/rails/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/rails/model/model_generator.rb +4 -0
- data/lib/rails/generators/rails/plugin/USAGE +17 -6
- data/lib/rails/generators/rails/plugin/plugin_generator.rb +43 -22
- data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +2 -2
- data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +7 -3
- data/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt +1 -1
- data/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +2 -0
- data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +1 -17
- data/lib/rails/generators/rails/plugin/templates/bin/rubocop.tt +7 -0
- data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +103 -0
- data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +12 -0
- data/lib/rails/generators/rails/plugin/templates/gitignore.tt +0 -2
- data/lib/rails/generators/rails/plugin/templates/rubocop.yml.tt +8 -0
- data/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt +1 -1
- data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +4 -4
- data/lib/rails/generators/rails/resource/resource_generator.rb +6 -0
- data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +2 -1
- data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +1 -1
- data/lib/rails/generators/test_case.rb +2 -2
- data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb.tt +6 -4
- data/lib/rails/generators/test_unit/mailer/templates/preview.rb.tt +3 -2
- data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +16 -2
- data/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt +2 -2
- data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +2 -2
- data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +2 -0
- data/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt +1 -1
- data/lib/rails/generators/testing/assertions.rb +20 -0
- data/lib/rails/generators/testing/{behaviour.rb → behavior.rb} +8 -4
- data/lib/rails/generators.rb +7 -15
- data/lib/rails/health_controller.rb +55 -0
- data/lib/rails/info.rb +3 -3
- data/lib/rails/info_controller.rb +31 -11
- data/lib/rails/mailers_controller.rb +29 -6
- data/lib/rails/paths.rb +15 -12
- data/lib/rails/pwa_controller.rb +15 -0
- data/lib/rails/rack/logger.rb +27 -16
- data/lib/rails/rackup/server.rb +15 -0
- data/lib/rails/railtie/configurable.rb +2 -2
- data/lib/rails/railtie/configuration.rb +14 -1
- data/lib/rails/railtie.rb +20 -21
- data/lib/rails/source_annotation_extractor.rb +67 -18
- data/lib/rails/tasks/engine.rake +8 -8
- data/lib/rails/tasks/framework.rake +2 -34
- data/lib/rails/tasks/log.rake +1 -1
- data/lib/rails/tasks/misc.rake +3 -14
- data/lib/rails/tasks/statistics.rake +5 -4
- data/lib/rails/tasks/tmp.rake +6 -6
- data/lib/rails/tasks/zeitwerk.rake +15 -35
- data/lib/rails/tasks.rb +0 -2
- data/lib/rails/templates/layouts/application.html.erb +1 -1
- data/lib/rails/templates/rails/mailers/email.html.erb +44 -8
- data/lib/rails/templates/rails/mailers/index.html.erb +14 -7
- data/lib/rails/templates/rails/mailers/mailer.html.erb +11 -5
- data/lib/rails/templates/rails/welcome/index.html.erb +5 -2
- data/lib/rails/test_help.rb +11 -18
- data/lib/rails/test_unit/line_filtering.rb +1 -1
- data/lib/rails/test_unit/reporter.rb +14 -4
- data/lib/rails/test_unit/runner.rb +62 -20
- data/lib/rails/test_unit/test_parser.rb +133 -0
- data/lib/rails/test_unit/testing.rake +13 -33
- data/lib/rails/testing/maintain_test_schema.rb +16 -0
- data/lib/rails/version.rb +1 -1
- data/lib/rails/zeitwerk_checker.rb +15 -0
- data/lib/rails.rb +20 -17
- metadata +89 -42
- data/RDOC_MAIN.rdoc +0 -97
- data/lib/rails/app_updater.rb +0 -40
- data/lib/rails/application/dummy_erb_compiler.rb +0 -18
- data/lib/rails/commands/secrets/USAGE +0 -66
- data/lib/rails/commands/secrets/secrets_command.rb +0 -65
- data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +0 -68
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +0 -70
- data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +0 -24
- data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +0 -62
- data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +0 -53
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt +0 -143
- data/lib/rails/generators/rails/app/templates/public/apple-touch-icon-precomposed.png +0 -0
- data/lib/rails/generators/rails/app/templates/public/apple-touch-icon.png +0 -0
- data/lib/rails/generators/rails/app/templates/public/favicon.ico +0 -0
- data/lib/rails/generators/rails/model/USAGE +0 -113
- data/lib/rails/ruby_version_check.rb +0 -15
- data/lib/rails/secrets.rb +0 -110
- data/lib/rails/tasks/middleware.rake +0 -9
- data/lib/rails/tasks/restart.rake +0 -9
@@ -7,49 +7,54 @@ require "active_support/encrypted_configuration"
|
|
7
7
|
module Rails
|
8
8
|
module Generators
|
9
9
|
class CredentialsGenerator < Base # :nodoc:
|
10
|
+
argument :content_path, default: "config/credentials.yml.enc"
|
11
|
+
argument :key_path, default: "config/master.key"
|
12
|
+
class_option :skip_secret_key_base, type: :boolean
|
13
|
+
|
10
14
|
def add_credentials_file
|
11
|
-
|
12
|
-
|
15
|
+
in_root do
|
16
|
+
return if File.exist?(content_path)
|
13
17
|
|
14
|
-
say "Adding #{
|
18
|
+
say "Adding #{content_path} to store encrypted credentials."
|
15
19
|
say ""
|
20
|
+
|
21
|
+
content = render_template_to_encrypted_file
|
22
|
+
|
16
23
|
say "The following content has been encrypted with the Rails master key:"
|
17
24
|
say ""
|
18
|
-
say
|
25
|
+
say content, :on_green
|
19
26
|
say ""
|
20
|
-
|
21
|
-
add_credentials_file_silently(template)
|
22
|
-
|
23
27
|
say "You can edit encrypted credentials with `bin/rails credentials:edit`."
|
24
28
|
say ""
|
25
29
|
end
|
26
30
|
end
|
27
31
|
|
28
|
-
def add_credentials_file_silently(template = nil)
|
29
|
-
unless credentials.content_path.exist?
|
30
|
-
credentials.write(credentials_template)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
32
|
private
|
35
|
-
def
|
33
|
+
def encrypted_file
|
36
34
|
ActiveSupport::EncryptedConfiguration.new(
|
37
|
-
config_path:
|
38
|
-
key_path:
|
35
|
+
config_path: content_path,
|
36
|
+
key_path: key_path,
|
39
37
|
env_key: "RAILS_MASTER_KEY",
|
40
38
|
raise_if_missing_key: true
|
41
39
|
)
|
42
40
|
end
|
43
41
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
42
|
+
def secret_key_base
|
43
|
+
@secret_key_base ||= SecureRandom.hex(64)
|
44
|
+
end
|
45
|
+
|
46
|
+
def render_template_to_encrypted_file
|
47
|
+
empty_directory File.dirname(content_path)
|
48
|
+
|
49
|
+
content = nil
|
50
|
+
|
51
|
+
encrypted_file.change do |tmp_path|
|
52
|
+
template("credentials.yml", tmp_path, force: true, verbose: false) do |rendered|
|
53
|
+
content = rendered
|
54
|
+
end
|
55
|
+
end
|
49
56
|
|
50
|
-
|
51
|
-
secret_key_base: #{SecureRandom.hex(64)}
|
52
|
-
YAML
|
57
|
+
content
|
53
58
|
end
|
54
59
|
end
|
55
60
|
end
|
@@ -1,15 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rails/generators/base"
|
4
|
+
require "yaml"
|
5
|
+
require "json"
|
4
6
|
|
5
7
|
module Rails
|
6
8
|
module Generators
|
7
9
|
module Db
|
8
10
|
module System
|
9
11
|
class ChangeGenerator < Base # :nodoc:
|
10
|
-
include Database
|
11
12
|
include AppName
|
12
13
|
|
14
|
+
BASE_PACKAGES = %w( curl libvips )
|
15
|
+
BUILD_PACKAGES = %w( build-essential git )
|
16
|
+
|
13
17
|
class_option :to, required: true,
|
14
18
|
desc: "The database system to switch to."
|
15
19
|
|
@@ -21,8 +25,8 @@ module Rails
|
|
21
25
|
def initialize(*)
|
22
26
|
super
|
23
27
|
|
24
|
-
unless DATABASES.include?(options[:to])
|
25
|
-
raise Error, "Invalid value for --to option. Supported preconfigurations are: #{DATABASES.join(", ")}."
|
28
|
+
unless Database::DATABASES.include?(options[:to])
|
29
|
+
raise Error, "Invalid value for --to option. Supported preconfigurations are: #{Database::DATABASES.join(", ")}."
|
26
30
|
end
|
27
31
|
|
28
32
|
opt = options.dup
|
@@ -35,14 +39,53 @@ module Rails
|
|
35
39
|
end
|
36
40
|
|
37
41
|
def edit_gemfile
|
38
|
-
name, version =
|
42
|
+
name, version = database.gem
|
39
43
|
gsub_file("Gemfile", all_database_gems_regex, name)
|
40
44
|
gsub_file("Gemfile", gem_entry_regex_for(name), gem_entry_for(name, *version))
|
41
45
|
end
|
42
46
|
|
47
|
+
def edit_dockerfile
|
48
|
+
dockerfile_path = File.expand_path("Dockerfile", destination_root)
|
49
|
+
return unless File.exist?(dockerfile_path)
|
50
|
+
|
51
|
+
gsub_file("Dockerfile", all_docker_bases_regex, docker_base_packages(database.base_package))
|
52
|
+
gsub_file("Dockerfile", all_docker_builds_regex, docker_build_packages(database.build_package))
|
53
|
+
end
|
54
|
+
|
55
|
+
def edit_devcontainer_files
|
56
|
+
return unless devcontainer?
|
57
|
+
|
58
|
+
edit_devcontainer_json
|
59
|
+
edit_compose_yaml
|
60
|
+
end
|
61
|
+
|
43
62
|
private
|
44
63
|
def all_database_gems
|
45
|
-
|
64
|
+
Database.all.map { |database| database.gem }
|
65
|
+
end
|
66
|
+
|
67
|
+
def all_docker_bases
|
68
|
+
Database.all.map { |database| docker_base_packages(database.base_package) }.uniq
|
69
|
+
end
|
70
|
+
|
71
|
+
def docker_base_packages(database_package)
|
72
|
+
if database_package
|
73
|
+
[database_package].concat(BASE_PACKAGES).sort
|
74
|
+
else
|
75
|
+
BASE_PACKAGES
|
76
|
+
end.join("\s")
|
77
|
+
end
|
78
|
+
|
79
|
+
def all_docker_builds
|
80
|
+
Database.all.map { |database| docker_build_packages(database.build_package) }.uniq
|
81
|
+
end
|
82
|
+
|
83
|
+
def docker_build_packages(database_package)
|
84
|
+
if database_package
|
85
|
+
[database_package].concat(BUILD_PACKAGES).sort
|
86
|
+
else
|
87
|
+
BUILD_PACKAGES
|
88
|
+
end.join("\s")
|
46
89
|
end
|
47
90
|
|
48
91
|
def all_database_gems_regex
|
@@ -50,6 +93,14 @@ module Rails
|
|
50
93
|
/(\b#{all_database_gem_names.join('\b|\b')}\b)/
|
51
94
|
end
|
52
95
|
|
96
|
+
def all_docker_bases_regex
|
97
|
+
/(\b#{all_docker_bases.join('\b|\b')}\b)/
|
98
|
+
end
|
99
|
+
|
100
|
+
def all_docker_builds_regex
|
101
|
+
/(\b#{all_docker_builds.join('\b|\b')}\b)/
|
102
|
+
end
|
103
|
+
|
53
104
|
def gem_entry_regex_for(gem_name)
|
54
105
|
/^gem.*\b#{gem_name}\b.*/
|
55
106
|
end
|
@@ -58,6 +109,96 @@ module Rails
|
|
58
109
|
gem_name_and_version.map! { |segment| "\"#{segment}\"" }
|
59
110
|
"gem #{gem_name_and_version.join(", ")}"
|
60
111
|
end
|
112
|
+
|
113
|
+
def edit_devcontainer_json
|
114
|
+
return unless devcontainer_json
|
115
|
+
|
116
|
+
update_devcontainer_db_host
|
117
|
+
update_devcontainer_db_feature
|
118
|
+
end
|
119
|
+
|
120
|
+
def edit_compose_yaml
|
121
|
+
compose_yaml_path = File.expand_path(".devcontainer/compose.yaml", destination_root)
|
122
|
+
return unless File.exist?(compose_yaml_path)
|
123
|
+
|
124
|
+
compose_config = YAML.load_file(compose_yaml_path)
|
125
|
+
|
126
|
+
Database.all.each do |database|
|
127
|
+
compose_config["services"].delete(database.name)
|
128
|
+
compose_config["volumes"]&.delete(database.volume)
|
129
|
+
compose_config["services"]["rails-app"]["depends_on"]&.delete(database.name)
|
130
|
+
end
|
131
|
+
|
132
|
+
if database.service
|
133
|
+
compose_config["services"][database.name] = database.service
|
134
|
+
compose_config["volumes"] = { database.volume => nil }.merge(compose_config["volumes"] || {})
|
135
|
+
compose_config["services"]["rails-app"]["depends_on"] = [
|
136
|
+
database.name,
|
137
|
+
compose_config["services"]["rails-app"]["depends_on"]
|
138
|
+
].flatten.compact
|
139
|
+
end
|
140
|
+
|
141
|
+
compose_config.delete("volumes") unless compose_config["volumes"]&.any?
|
142
|
+
compose_config["services"]["rails-app"].delete("depends_on") unless compose_config["services"]["rails-app"]["depends_on"]&.any?
|
143
|
+
|
144
|
+
File.write(compose_yaml_path, compose_config.to_yaml)
|
145
|
+
end
|
146
|
+
|
147
|
+
def update_devcontainer_db_host
|
148
|
+
container_env = devcontainer_json["containerEnv"]
|
149
|
+
db_name = database.name
|
150
|
+
|
151
|
+
if container_env["DB_HOST"]
|
152
|
+
if database.service
|
153
|
+
container_env["DB_HOST"] = db_name
|
154
|
+
else
|
155
|
+
container_env.delete("DB_HOST")
|
156
|
+
end
|
157
|
+
else
|
158
|
+
if database.service
|
159
|
+
container_env["DB_HOST"] = db_name
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
new_json = JSON.pretty_generate(container_env, indent: " ", object_nl: "\n ")
|
164
|
+
|
165
|
+
gsub_file(".devcontainer/devcontainer.json", /("containerEnv"\s*:\s*)(.|\n)*?(^\s{2}})/, "\\1#{new_json}")
|
166
|
+
end
|
167
|
+
|
168
|
+
def update_devcontainer_db_feature
|
169
|
+
features = devcontainer_json["features"]
|
170
|
+
db_feature = database.feature
|
171
|
+
|
172
|
+
Database.all.each do |database|
|
173
|
+
features.delete(database.feature_name)
|
174
|
+
end
|
175
|
+
|
176
|
+
features.merge!(db_feature) if db_feature
|
177
|
+
|
178
|
+
new_json = JSON.pretty_generate(features, indent: " ", object_nl: "\n ")
|
179
|
+
|
180
|
+
gsub_file(".devcontainer/devcontainer.json", /("features"\s*:\s*)(.|\n)*?(^\s{2}})/, "\\1#{new_json}")
|
181
|
+
end
|
182
|
+
|
183
|
+
def devcontainer_json
|
184
|
+
return unless File.exist?(devcontainer_json_path)
|
185
|
+
|
186
|
+
@devcontainer_json ||= JSON.parse(File.read(devcontainer_json_path))
|
187
|
+
end
|
188
|
+
|
189
|
+
def devcontainer_json_path
|
190
|
+
File.expand_path(".devcontainer/devcontainer.json", destination_root)
|
191
|
+
end
|
192
|
+
|
193
|
+
def database
|
194
|
+
@database ||= Database.build(options[:database])
|
195
|
+
end
|
196
|
+
|
197
|
+
def devcontainer?
|
198
|
+
return @devcontainer if defined?(@devcontainer)
|
199
|
+
|
200
|
+
@devcontainer = File.exist?(File.expand_path(".devcontainer", destination_root))
|
201
|
+
end
|
61
202
|
end
|
62
203
|
end
|
63
204
|
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
|
5
|
+
module Rails
|
6
|
+
module Generators
|
7
|
+
class DevcontainerGenerator < Base # :nodoc:
|
8
|
+
class_option :app_name, type: :string, default: "rails_app",
|
9
|
+
desc: "Name of the app"
|
10
|
+
|
11
|
+
class_option :database, enum: Database::DATABASES, type: :string, default: "sqlite3",
|
12
|
+
desc: "Include configuration for selected database"
|
13
|
+
|
14
|
+
class_option :redis, type: :boolean, default: true,
|
15
|
+
desc: "Include configuration for Redis"
|
16
|
+
|
17
|
+
class_option :system_test, type: :boolean, default: true,
|
18
|
+
desc: "Include configuration for System Tests"
|
19
|
+
|
20
|
+
class_option :active_storage, type: :boolean, default: true,
|
21
|
+
desc: "Include configuration for Active Storage"
|
22
|
+
|
23
|
+
class_option :node, type: :boolean, default: false,
|
24
|
+
desc: "Include configuration for Node"
|
25
|
+
|
26
|
+
class_option :dev, type: :boolean, default: false,
|
27
|
+
desc: "For applications pointing to a local Rails checkout"
|
28
|
+
|
29
|
+
source_paths << File.expand_path(File.join(base_name, "app", "templates"), base_root)
|
30
|
+
|
31
|
+
def create_devcontainer
|
32
|
+
empty_directory ".devcontainer"
|
33
|
+
|
34
|
+
template "devcontainer/devcontainer.json", ".devcontainer/devcontainer.json"
|
35
|
+
template "devcontainer/Dockerfile", ".devcontainer/Dockerfile"
|
36
|
+
template "devcontainer/compose.yaml", ".devcontainer/compose.yaml"
|
37
|
+
end
|
38
|
+
|
39
|
+
def update_application_system_test_case
|
40
|
+
return unless options[:system_test]
|
41
|
+
return unless File.exist?("test/application_system_test_case.rb")
|
42
|
+
|
43
|
+
gsub_file("test/application_system_test_case.rb", /^\s*driven_by\b.*/, system_test_configuration)
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_database_yml
|
47
|
+
# Only postgresql has devcontainer specific configuration, so only update database.yml if we are using postgres
|
48
|
+
return unless options[:database] == "postgresql"
|
49
|
+
|
50
|
+
template("config/databases/#{options[:database]}.yml", "config/database.yml")
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def devcontainer?
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def app_name
|
59
|
+
options[:app_name]
|
60
|
+
end
|
61
|
+
|
62
|
+
def dependencies
|
63
|
+
return @dependencies if @dependencies
|
64
|
+
|
65
|
+
@dependencies = []
|
66
|
+
|
67
|
+
@dependencies << "selenium" if options[:system_test]
|
68
|
+
@dependencies << "redis" if options[:redis]
|
69
|
+
@dependencies << database.name if database.service
|
70
|
+
@dependencies
|
71
|
+
end
|
72
|
+
|
73
|
+
def container_env
|
74
|
+
return @container_env if @container_env
|
75
|
+
|
76
|
+
@container_env = {}
|
77
|
+
|
78
|
+
@container_env["CAPYBARA_SERVER_PORT"] = "45678" if options[:system_test]
|
79
|
+
@container_env["SELENIUM_HOST"] = "selenium" if options[:system_test]
|
80
|
+
@container_env["REDIS_URL"] = "redis://redis:6379/1" if options[:redis]
|
81
|
+
@container_env["DB_HOST"] = database.name if database.service
|
82
|
+
|
83
|
+
@container_env
|
84
|
+
end
|
85
|
+
|
86
|
+
def volumes
|
87
|
+
return @volumes if @volumes
|
88
|
+
|
89
|
+
@volumes = []
|
90
|
+
|
91
|
+
@volumes << "redis-data" if options[:redis]
|
92
|
+
@volumes << database.volume if database.volume
|
93
|
+
|
94
|
+
@volumes
|
95
|
+
end
|
96
|
+
|
97
|
+
def features
|
98
|
+
return @features if @features
|
99
|
+
|
100
|
+
@features = {
|
101
|
+
"ghcr.io/devcontainers/features/github-cli:1" => {}
|
102
|
+
}
|
103
|
+
|
104
|
+
@features["ghcr.io/rails/devcontainer/features/activestorage"] = {} if options[:active_storage]
|
105
|
+
@features["ghcr.io/devcontainers/features/node:1"] = {} if options[:node]
|
106
|
+
|
107
|
+
@features.merge!(database.feature) if database.feature
|
108
|
+
|
109
|
+
@features
|
110
|
+
end
|
111
|
+
|
112
|
+
def mounts
|
113
|
+
return @mounts if @mounts
|
114
|
+
|
115
|
+
@mounts = []
|
116
|
+
|
117
|
+
@mounts << local_rails_mount if options[:dev]
|
118
|
+
|
119
|
+
@mounts
|
120
|
+
end
|
121
|
+
|
122
|
+
def forward_ports
|
123
|
+
return @forward_ports if @forward_ports
|
124
|
+
|
125
|
+
@forward_ports = [3000]
|
126
|
+
@forward_ports << database.port if database.port
|
127
|
+
@forward_ports << 6379 if options[:redis]
|
128
|
+
|
129
|
+
@forward_ports
|
130
|
+
end
|
131
|
+
|
132
|
+
def database
|
133
|
+
@database ||= Database.build(options[:database])
|
134
|
+
end
|
135
|
+
|
136
|
+
def devcontainer_db_service_yaml(**options)
|
137
|
+
return unless service = database.service
|
138
|
+
|
139
|
+
{ database.name => service }.to_yaml(**options)[4..-1]
|
140
|
+
end
|
141
|
+
|
142
|
+
def local_rails_mount
|
143
|
+
{
|
144
|
+
type: "bind",
|
145
|
+
source: Rails::Generators::RAILS_DEV_PATH,
|
146
|
+
target: Rails::Generators::RAILS_DEV_PATH
|
147
|
+
}
|
148
|
+
end
|
149
|
+
|
150
|
+
def system_test_configuration
|
151
|
+
optimize_indentation(<<-'RUBY', 2)
|
152
|
+
if ENV["CAPYBARA_SERVER_PORT"]
|
153
|
+
served_by host: "rails-app", port: ENV["CAPYBARA_SERVER_PORT"]
|
154
|
+
|
155
|
+
driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ], options: {
|
156
|
+
browser: :remote,
|
157
|
+
url: "http://#{ENV["SELENIUM_HOST"]}:4444"
|
158
|
+
}
|
159
|
+
else
|
160
|
+
driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ]
|
161
|
+
end
|
162
|
+
RUBY
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
name: "<%= options[:app_name] %>"
|
2
|
+
|
3
|
+
services:
|
4
|
+
rails-app:
|
5
|
+
build:
|
6
|
+
context: ..
|
7
|
+
dockerfile: .devcontainer/Dockerfile
|
8
|
+
|
9
|
+
volumes:
|
10
|
+
- ../..:/workspaces:cached
|
11
|
+
|
12
|
+
# Overrides default command so things don't shut down after the process ends.
|
13
|
+
command: sleep infinity
|
14
|
+
|
15
|
+
# Uncomment the next line to use a non-root user for all processes.
|
16
|
+
# user: vscode
|
17
|
+
|
18
|
+
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
|
19
|
+
# (Adding the "ports" property to this file will not forward from a Codespace.)
|
20
|
+
<%- if !dependencies.empty? -%>
|
21
|
+
depends_on:
|
22
|
+
<%- dependencies.each do |dependency| -%>
|
23
|
+
- <%= dependency %>
|
24
|
+
<%- end -%>
|
25
|
+
<%- end -%>
|
26
|
+
<%- if options[:system_test] -%>
|
27
|
+
|
28
|
+
selenium:
|
29
|
+
image: selenium/standalone-chromium
|
30
|
+
restart: unless-stopped
|
31
|
+
<%- end -%>
|
32
|
+
|
33
|
+
<%- if options[:redis] -%>
|
34
|
+
redis:
|
35
|
+
image: redis:7.2
|
36
|
+
restart: unless-stopped
|
37
|
+
volumes:
|
38
|
+
- redis-data:/data
|
39
|
+
|
40
|
+
<%- end -%>
|
41
|
+
<%= devcontainer_db_service_yaml(indentation: 4) %>
|
42
|
+
<%- if !volumes.empty? -%>
|
43
|
+
volumes:
|
44
|
+
<%- volumes.each do |volume| -%>
|
45
|
+
<%= volume %>:
|
46
|
+
<%- end -%>
|
47
|
+
<%- end -%>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
2
|
+
// README at: https://github.com/devcontainers/templates/tree/main/src/ruby
|
3
|
+
{
|
4
|
+
"name": "<%= options[:app_name] %>",
|
5
|
+
"dockerComposeFile": "compose.yaml",
|
6
|
+
"service": "rails-app",
|
7
|
+
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
8
|
+
|
9
|
+
// Features to add to the dev container. More info: https://containers.dev/features.
|
10
|
+
"features": {
|
11
|
+
<%= features.map { |key, value| "\"#{key}\": #{value.as_json}" }.join(",\n ") %>
|
12
|
+
},
|
13
|
+
|
14
|
+
<%- if !container_env.empty? -%>
|
15
|
+
"containerEnv": {
|
16
|
+
<%= container_env.map { |key, value| "\"#{key}\": \"#{value}\"" }.join(",\n ") %>
|
17
|
+
},
|
18
|
+
<%- end -%>
|
19
|
+
|
20
|
+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
21
|
+
"forwardPorts": <%= forward_ports.as_json %>,
|
22
|
+
|
23
|
+
// Configure tool-specific properties.
|
24
|
+
// "customizations": {},
|
25
|
+
|
26
|
+
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
27
|
+
// "remoteUser": "root",
|
28
|
+
|
29
|
+
<%- if !mounts.empty? -%>
|
30
|
+
"mounts": [
|
31
|
+
<%= mounts.map { |mount| "{\n " + mount.map { |key, value| "\"#{key}\": \"#{value}\"" }.join(",\n ") + "\n }" }.join(",\n ") %>
|
32
|
+
],
|
33
|
+
<%- end -%>
|
34
|
+
|
35
|
+
// Use 'postCreateCommand' to run commands after the container is created.
|
36
|
+
"postCreateCommand": "bin/setup"
|
37
|
+
}
|
@@ -26,8 +26,7 @@ module Rails
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def add_key_file_silently(key_path, key = nil)
|
29
|
-
create_file key_path, key || ActiveSupport::EncryptedFile.generate_key
|
30
|
-
key_path.chmod 0600
|
29
|
+
create_file key_path, key || ActiveSupport::EncryptedFile.generate_key, perm: 0600
|
31
30
|
end
|
32
31
|
|
33
32
|
def ignore_key_file(key_path, ignore: key_ignore(key_path))
|
@@ -5,31 +5,41 @@ Description:
|
|
5
5
|
A migration class is generated in db/migrate prefixed by a timestamp of the current date and time.
|
6
6
|
|
7
7
|
You can name your migration in either of these formats to generate add/remove
|
8
|
-
column lines from supplied attributes:
|
8
|
+
column lines from supplied attributes: add_{columns}_to_{table} or remove_{columns}_from_{table}.
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
A migration name containing JoinTable will generate join tables for use with
|
11
|
+
has_and_belongs_to_many associations.
|
12
|
+
|
13
|
+
You can also name your migration create_{table} along with any attributes to generate a regular table.
|
14
|
+
|
15
|
+
Examples:
|
16
|
+
`bin/rails generate migration add_ssl_flag`
|
12
17
|
|
13
18
|
If the current date is May 14, 2008 and the current time 09:09:12, this creates the AddSslFlag migration
|
14
19
|
db/migrate/20080514090912_add_ssl_flag.rb
|
15
20
|
|
16
|
-
`bin/rails generate migration
|
21
|
+
`bin/rails generate migration add_title_body_published_to_post title:string body:text published:boolean`
|
17
22
|
|
18
|
-
This will create
|
23
|
+
This will create db/migrate/20080514090912_add_title_body_published_to_post.rb with this in the migration:
|
19
24
|
|
20
25
|
add_column :posts, :title, :string
|
21
26
|
add_column :posts, :body, :text
|
22
27
|
add_column :posts, :published, :boolean
|
23
28
|
|
24
|
-
|
25
|
-
has_and_belongs_to_many associations.
|
29
|
+
`bin/rails generate migration create_media_join_table artists musics:uniq`
|
26
30
|
|
27
|
-
|
28
|
-
`bin/rails g migration CreateMediaJoinTable artists musics:uniq`
|
29
|
-
|
30
|
-
will create the migration
|
31
|
+
This will create a join table migration:
|
31
32
|
|
32
33
|
create_join_table :artists, :musics do |t|
|
33
34
|
# t.index [:artist_id, :music_id]
|
34
35
|
t.index [:music_id, :artist_id], unique: true
|
35
36
|
end
|
37
|
+
|
38
|
+
`bin/rails generate migration create_users email:string`
|
39
|
+
|
40
|
+
This will create the migration:
|
41
|
+
|
42
|
+
create_table :users do |t|
|
43
|
+
t.string :email
|
44
|
+
t.timestamps
|
45
|
+
end
|
@@ -5,6 +5,10 @@ module Rails
|
|
5
5
|
class MigrationGenerator < NamedBase # :nodoc:
|
6
6
|
argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
|
7
7
|
hook_for :orm, required: true, desc: "ORM to be invoked"
|
8
|
+
|
9
|
+
def self.exit_on_failure? # :nodoc:
|
10
|
+
true
|
11
|
+
end
|
8
12
|
end
|
9
13
|
end
|
10
14
|
end
|
@@ -9,6 +9,10 @@ module Rails
|
|
9
9
|
|
10
10
|
argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
|
11
11
|
hook_for :orm, required: true, desc: "ORM to be invoked"
|
12
|
+
|
13
|
+
class << self
|
14
|
+
delegate(:desc, to: :orm_generator)
|
15
|
+
end
|
12
16
|
end
|
13
17
|
end
|
14
18
|
end
|
@@ -1,10 +1,21 @@
|
|
1
1
|
Description:
|
2
|
-
The
|
3
|
-
|
4
|
-
|
2
|
+
The `rails plugin new` command creates a Rails plugin with the ability
|
3
|
+
to run tests using a dummy Rails application. A plugin is a gem with
|
4
|
+
either a railtie or an engine.
|
5
5
|
|
6
|
-
|
7
|
-
rails plugin new ~/Code/Ruby/blog
|
6
|
+
Examples:
|
7
|
+
`rails plugin new ~/Code/Ruby/blog`
|
8
8
|
|
9
|
-
This generates a
|
9
|
+
This generates a Rails railtie gem in ~/Code/Ruby/blog.
|
10
10
|
See the README in the newly created plugin to get going.
|
11
|
+
|
12
|
+
`rails plugin new blog --full`
|
13
|
+
|
14
|
+
This generates a full Rails engine gem in ./blog. The `--mountable`
|
15
|
+
option may also be used to generate a mountable, namespace-isolated
|
16
|
+
engine with assets and layouts.
|
17
|
+
|
18
|
+
`rails plugin new blog --mountable --skip-asset-pipeline`
|
19
|
+
|
20
|
+
This generates a mountable Rails engine gem at ./blog without an asset
|
21
|
+
pipeline. Any part of Rails can be skipped during plugin generation.
|