railties 7.0.5 → 7.1.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +710 -188
  3. data/MIT-LICENSE +1 -1
  4. data/RDOC_MAIN.md +99 -0
  5. data/README.rdoc +5 -5
  6. data/lib/minitest/rails_plugin.rb +63 -0
  7. data/lib/rails/api/task.rb +35 -4
  8. data/lib/rails/app_updater.rb +1 -1
  9. data/lib/rails/application/bootstrap.rb +23 -4
  10. data/lib/rails/application/configuration.rb +190 -70
  11. data/lib/rails/application/default_middleware_stack.rb +8 -2
  12. data/lib/rails/application/dummy_config.rb +19 -0
  13. data/lib/rails/application/finisher.rb +43 -33
  14. data/lib/rails/application.rb +134 -29
  15. data/lib/rails/backtrace_cleaner.rb +1 -1
  16. data/lib/rails/cli.rb +5 -2
  17. data/lib/rails/command/actions.rb +10 -12
  18. data/lib/rails/command/base.rb +55 -53
  19. data/lib/rails/command/environment_argument.rb +32 -16
  20. data/lib/rails/command/helpers/editor.rb +17 -12
  21. data/lib/rails/command.rb +84 -33
  22. data/lib/rails/commands/about/about_command.rb +14 -0
  23. data/lib/rails/commands/application/application_command.rb +2 -0
  24. data/lib/rails/commands/console/console_command.rb +14 -14
  25. data/lib/rails/commands/credentials/USAGE +53 -55
  26. data/lib/rails/commands/credentials/credentials_command/diffing.rb +5 -3
  27. data/lib/rails/commands/credentials/credentials_command.rb +64 -70
  28. data/lib/rails/commands/db/system/change/change_command.rb +2 -1
  29. data/lib/rails/commands/dbconsole/dbconsole_command.rb +25 -115
  30. data/lib/rails/commands/destroy/destroy_command.rb +3 -2
  31. data/lib/rails/commands/dev/dev_command.rb +1 -6
  32. data/lib/rails/commands/encrypted/USAGE +15 -20
  33. data/lib/rails/commands/encrypted/encrypted_command.rb +46 -35
  34. data/lib/rails/commands/gem_help/USAGE +16 -0
  35. data/lib/rails/commands/gem_help/gem_help_command.rb +13 -0
  36. data/lib/rails/commands/generate/generate_command.rb +2 -2
  37. data/lib/rails/commands/help/USAGE +13 -13
  38. data/lib/rails/commands/help/help_command.rb +21 -2
  39. data/lib/rails/commands/initializers/initializers_command.rb +1 -4
  40. data/lib/rails/commands/middleware/middleware_command.rb +17 -0
  41. data/lib/rails/commands/new/new_command.rb +2 -0
  42. data/lib/rails/commands/notes/notes_command.rb +2 -1
  43. data/lib/rails/commands/plugin/plugin_command.rb +2 -0
  44. data/lib/rails/commands/rake/rake_command.rb +25 -22
  45. data/lib/rails/commands/restart/restart_command.rb +14 -0
  46. data/lib/rails/commands/routes/routes_command.rb +13 -1
  47. data/lib/rails/commands/runner/USAGE +14 -12
  48. data/lib/rails/commands/runner/runner_command.rb +32 -20
  49. data/lib/rails/commands/secret/secret_command.rb +13 -0
  50. data/lib/rails/commands/secrets/USAGE +44 -49
  51. data/lib/rails/commands/secrets/secrets_command.rb +20 -38
  52. data/lib/rails/commands/server/server_command.rb +33 -32
  53. data/lib/rails/commands/test/USAGE +14 -0
  54. data/lib/rails/commands/test/test_command.rb +56 -14
  55. data/lib/rails/commands/unused_routes/unused_routes_command.rb +75 -0
  56. data/lib/rails/commands/version/version_command.rb +1 -0
  57. data/lib/rails/configuration.rb +5 -5
  58. data/lib/rails/console/app.rb +1 -4
  59. data/lib/rails/deprecator.rb +7 -0
  60. data/lib/rails/engine/configuration.rb +50 -6
  61. data/lib/rails/engine.rb +49 -21
  62. data/lib/rails/gem_version.rb +4 -4
  63. data/lib/rails/generators/actions.rb +178 -59
  64. data/lib/rails/generators/active_model.rb +28 -14
  65. data/lib/rails/generators/app_base.rb +355 -82
  66. data/lib/rails/generators/app_name.rb +3 -14
  67. data/lib/rails/generators/base.rb +17 -9
  68. data/lib/rails/generators/database.rb +39 -1
  69. data/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt +1 -1
  70. data/lib/rails/generators/generated_attribute.rb +12 -0
  71. data/lib/rails/generators/migration.rb +1 -2
  72. data/lib/rails/generators/model_helpers.rb +2 -1
  73. data/lib/rails/generators/rails/app/USAGE +22 -6
  74. data/lib/rails/generators/rails/app/app_generator.rb +85 -64
  75. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +103 -0
  76. data/lib/rails/generators/rails/app/templates/Gemfile.tt +10 -10
  77. data/lib/rails/generators/rails/app/templates/app/views/layouts/mailer.html.erb.tt +1 -1
  78. data/lib/rails/generators/rails/app/templates/bin/setup.tt +10 -1
  79. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +6 -17
  80. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +4 -4
  81. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +3 -3
  82. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +4 -6
  83. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +3 -3
  84. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +59 -0
  85. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +12 -2
  86. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +32 -28
  87. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +13 -9
  88. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +2 -0
  89. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +2 -2
  90. data/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt +1 -1
  91. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +3 -3
  92. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_1.rb.tt +284 -0
  93. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +11 -9
  94. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +11 -13
  95. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +11 -19
  96. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +5 -1
  97. data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +6 -4
  98. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +10 -0
  99. data/lib/rails/generators/rails/app/templates/dockerignore.tt +43 -0
  100. data/lib/rails/generators/rails/app/templates/gitignore.tt +4 -8
  101. data/lib/rails/generators/rails/app/templates/node-version.tt +1 -0
  102. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +10 -8
  103. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +9 -7
  104. data/lib/rails/generators/rails/application_record/application_record_generator.rb +4 -0
  105. data/lib/rails/generators/rails/benchmark/benchmark_generator.rb +2 -1
  106. data/lib/rails/generators/rails/controller/USAGE +12 -4
  107. data/lib/rails/generators/rails/controller/controller_generator.rb +5 -0
  108. data/lib/rails/generators/rails/controller/templates/controller.rb.tt +1 -1
  109. data/lib/rails/generators/rails/credentials/credentials_generator.rb +29 -24
  110. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +8 -0
  111. data/lib/rails/generators/rails/db/system/change/change_generator.rb +30 -0
  112. data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +1 -2
  113. data/lib/rails/generators/rails/migration/USAGE +21 -11
  114. data/lib/rails/generators/rails/model/model_generator.rb +4 -0
  115. data/lib/rails/generators/rails/plugin/USAGE +17 -6
  116. data/lib/rails/generators/rails/plugin/plugin_generator.rb +5 -15
  117. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +2 -2
  118. data/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt +1 -1
  119. data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +1 -17
  120. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +0 -2
  121. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +4 -4
  122. data/lib/rails/generators/rails/resource/resource_generator.rb +6 -0
  123. data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +2 -1
  124. data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +1 -1
  125. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +1 -1
  126. data/lib/rails/generators/test_case.rb +2 -2
  127. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +1 -1
  128. data/lib/rails/generators/testing/{behaviour.rb → behavior.rb} +4 -1
  129. data/lib/rails/generators.rb +6 -14
  130. data/lib/rails/health_controller.rb +55 -0
  131. data/lib/rails/info.rb +1 -1
  132. data/lib/rails/info_controller.rb +31 -11
  133. data/lib/rails/mailers_controller.rb +15 -5
  134. data/lib/rails/paths.rb +13 -10
  135. data/lib/rails/rack/logger.rb +15 -12
  136. data/lib/rails/rackup/server.rb +15 -0
  137. data/lib/rails/railtie/configuration.rb +14 -1
  138. data/lib/rails/railtie.rb +18 -18
  139. data/lib/rails/ruby_version_check.rb +2 -0
  140. data/lib/rails/secrets.rb +10 -8
  141. data/lib/rails/source_annotation_extractor.rb +67 -18
  142. data/lib/rails/tasks/engine.rake +8 -8
  143. data/lib/rails/tasks/framework.rake +4 -10
  144. data/lib/rails/tasks/log.rake +1 -1
  145. data/lib/rails/tasks/misc.rake +3 -14
  146. data/lib/rails/tasks/statistics.rake +5 -4
  147. data/lib/rails/tasks/tmp.rake +5 -5
  148. data/lib/rails/tasks/zeitwerk.rake +15 -35
  149. data/lib/rails/tasks.rb +0 -2
  150. data/lib/rails/templates/rails/mailers/email.html.erb +32 -0
  151. data/lib/rails/templates/rails/mailers/index.html.erb +14 -7
  152. data/lib/rails/templates/rails/mailers/mailer.html.erb +11 -5
  153. data/lib/rails/templates/rails/welcome/index.html.erb +1 -0
  154. data/lib/rails/test_help.rb +9 -14
  155. data/lib/rails/test_unit/line_filtering.rb +1 -1
  156. data/lib/rails/test_unit/reporter.rb +6 -2
  157. data/lib/rails/test_unit/runner.rb +36 -18
  158. data/lib/rails/test_unit/test_parser.rb +88 -0
  159. data/lib/rails/test_unit/testing.rake +13 -33
  160. data/lib/rails/testing/maintain_test_schema.rb +16 -0
  161. data/lib/rails/version.rb +1 -1
  162. data/lib/rails/zeitwerk_checker.rb +15 -0
  163. data/lib/rails.rb +15 -15
  164. metadata +69 -32
  165. data/RDOC_MAIN.rdoc +0 -97
  166. data/lib/rails/application/dummy_erb_compiler.rb +0 -18
  167. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt +0 -148
  168. data/lib/rails/generators/rails/model/USAGE +0 -113
  169. data/lib/rails/tasks/middleware.rake +0 -9
  170. data/lib/rails/tasks/restart.rake +0 -9
@@ -7,26 +7,15 @@ module Rails
7
7
 
8
8
  private
9
9
  def app_name
10
- @app_name ||= original_app_name.tr("\\", "").tr("-. ", "_")
10
+ @app_name ||= original_app_name.parameterize(preserve_case: true).underscore
11
11
  end
12
12
 
13
13
  def original_app_name
14
- @original_app_name ||= defined_app_const_base? ? defined_app_name : File.basename(destination_root)
14
+ @original_app_name ||= (options[:name] || File.basename(destination_root))
15
15
  end
16
16
 
17
- def defined_app_name
18
- defined_app_const_base.underscore
19
- end
20
-
21
- def defined_app_const_base
22
- Rails.respond_to?(:application) && defined?(Rails::Application) &&
23
- Rails.application.is_a?(Rails::Application) && Rails.application.class.name.chomp("::Application")
24
- end
25
-
26
- alias :defined_app_const_base? :defined_app_const_base
27
-
28
17
  def app_const_base
29
- @app_const_base ||= defined_app_const_base || app_name.gsub(/\W/, "_").squeeze("_").camelize
18
+ @app_const_base ||= app_name.gsub(/\W/, "_").squeeze("_").camelize
30
19
  end
31
20
  alias :camelized :app_const_base
32
21
 
@@ -79,15 +79,15 @@ module Rails
79
79
  #
80
80
  # For example, if the user invoke the controller generator as:
81
81
  #
82
- # bin/rails generate controller Account --test-framework=test_unit
82
+ # $ bin/rails generate controller Account --test-framework=test_unit
83
83
  #
84
84
  # The controller generator will then try to invoke the following generators:
85
85
  #
86
86
  # "rails:test_unit", "test_unit:controller", "test_unit"
87
87
  #
88
88
  # Notice that "rails:generators:test_unit" could be loaded as well, what
89
- # Rails looks for is the first and last parts of the namespace. This is what
90
- # allows any test framework to hook into Rails as long as it provides any
89
+ # \Rails looks for is the first and last parts of the namespace. This is what
90
+ # allows any test framework to hook into \Rails as long as it provides any
91
91
  # of the hooks above.
92
92
  #
93
93
  # ==== Options
@@ -134,11 +134,11 @@ module Rails
134
134
  # All hooks come with switches for user interface. If you do not want
135
135
  # to use any test framework, you can do:
136
136
  #
137
- # bin/rails generate controller Account --skip-test-framework
137
+ # $ bin/rails generate controller Account --skip-test-framework
138
138
  #
139
139
  # Or similarly:
140
140
  #
141
- # bin/rails generate controller Account --no-test-framework
141
+ # $ bin/rails generate controller Account --no-test-framework
142
142
  #
143
143
  # ==== Boolean hooks
144
144
  #
@@ -150,7 +150,7 @@ module Rails
150
150
  #
151
151
  # Then, if you want webrat to be invoked, just supply:
152
152
  #
153
- # bin/rails generate controller Account --webrat
153
+ # $ bin/rails generate controller Account --webrat
154
154
  #
155
155
  # The hooks lookup is similar as above:
156
156
  #
@@ -189,6 +189,13 @@ module Rails
189
189
  class_option(name, defaults.merge!(options))
190
190
  end
191
191
 
192
+ klass = self
193
+
194
+ singleton_class.define_method("#{name}_generator") do
195
+ value = class_options[name].default
196
+ Rails::Generators.find_by_namespace(klass.generator_name, value)
197
+ end
198
+
192
199
  hooks[name] = [ in_base, as_hook ]
193
200
  invoke_from_option(name, options, &block)
194
201
  end
@@ -201,6 +208,7 @@ module Rails
201
208
  remove_invocation(*names)
202
209
 
203
210
  names.each do |name|
211
+ singleton_class.undef_method("#{name}_generator")
204
212
  hooks.delete(name)
205
213
  end
206
214
  end
@@ -214,7 +222,7 @@ module Rails
214
222
  end
215
223
 
216
224
  # Returns the default source root for a given generator. This is used internally
217
- # by rails to set its generators source root. If you want to customize your source
225
+ # by \Rails to set its generators source root. If you want to customize your source
218
226
  # root, you should use source_root.
219
227
  def self.default_source_root
220
228
  return unless base_name && generator_name
@@ -317,9 +325,9 @@ module Rails
317
325
  @namespaced_path ||= namespace_dirs.join("/")
318
326
  end
319
327
 
320
- # Use Rails default banner.
328
+ # Use \Rails default banner.
321
329
  def self.banner # :doc:
322
- "rails generate #{namespace.delete_prefix("rails:")} #{arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, " ")
330
+ "bin/rails generate #{namespace.delete_prefix("rails:")} #{arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, " ")
323
331
  end
324
332
 
325
333
  # Sets the base_name taking into account the current class namespace.
@@ -4,7 +4,7 @@ module Rails
4
4
  module Generators
5
5
  module Database # :nodoc:
6
6
  JDBC_DATABASES = %w( jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc )
7
- DATABASES = %w( mysql postgresql sqlite3 oracle sqlserver ) + JDBC_DATABASES
7
+ DATABASES = %w( mysql trilogy postgresql sqlite3 oracle sqlserver ) + JDBC_DATABASES
8
8
 
9
9
  def initialize(*)
10
10
  super
@@ -14,6 +14,7 @@ module Rails
14
14
  def gem_for_database(database = options[:database])
15
15
  case database
16
16
  when "mysql" then ["mysql2", ["~> 0.5"]]
17
+ when "trilogy" then ["trilogy", ["~> 2.4"]]
17
18
  when "postgresql" then ["pg", ["~> 1.1"]]
18
19
  when "sqlite3" then ["sqlite3", ["~> 1.4"]]
19
20
  when "oracle" then ["activerecord-oracle_enhanced-adapter", nil]
@@ -26,6 +27,26 @@ module Rails
26
27
  end
27
28
  end
28
29
 
30
+ def docker_for_database_build(database = options[:database])
31
+ case database
32
+ when "mysql" then "build-essential default-libmysqlclient-dev git"
33
+ when "trilogy" then "build-essential default-libmysqlclient-dev git"
34
+ when "postgresql" then "build-essential git libpq-dev"
35
+ when "sqlite3" then "build-essential git"
36
+ else nil
37
+ end
38
+ end
39
+
40
+ def docker_for_database_deploy(database = options[:database])
41
+ case database
42
+ when "mysql" then "curl default-mysql-client libvips"
43
+ when "trilogy" then "curl default-mysql-client libvips"
44
+ when "postgresql" then "curl libvips postgresql-client"
45
+ when "sqlite3" then "curl libsqlite3-0 libvips"
46
+ else nil
47
+ end
48
+ end
49
+
29
50
  def convert_database_option_for_jruby
30
51
  if defined?(JRUBY_VERSION)
31
52
  opt = options.dup
@@ -38,6 +59,23 @@ module Rails
38
59
  end
39
60
  end
40
61
 
62
+ def build_package_for_database(database = options[:database])
63
+ case database
64
+ when "mysql" then "default-libmysqlclient-dev"
65
+ when "postgresql" then "libpq-dev"
66
+ else nil
67
+ end
68
+ end
69
+
70
+ def deploy_package_for_database(database = options[:database])
71
+ case database
72
+ when "mysql" then "default-mysql-client"
73
+ when "postgresql" then "postgresql-client"
74
+ when "sqlite3" then "libsqlite3-0"
75
+ else nil
76
+ end
77
+ end
78
+
41
79
  private
42
80
  def mysql_socket
43
81
  @mysql_socket ||= [
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
5
  <style>
6
6
  /* Email styles need to be inline */
7
7
  </style>
@@ -43,6 +43,10 @@ module Rails
43
43
  type, attr_options = *parse_type_and_options(type)
44
44
  type = type.to_sym if type
45
45
 
46
+ if dangerous_name?(name)
47
+ raise Error, "Could not generate field '#{name}', as it is already defined by Active Record."
48
+ end
49
+
46
50
  if type && !valid_type?(type)
47
51
  raise Error, "Could not generate field '#{name}' with unknown type '#{type}'."
48
52
  end
@@ -60,8 +64,14 @@ module Rails
60
64
  new(name, type, index_type, attr_options)
61
65
  end
62
66
 
67
+ def dangerous_name?(name)
68
+ defined?(ActiveRecord::Base) &&
69
+ ActiveRecord::Base.dangerous_attribute_method?(name)
70
+ end
71
+
63
72
  def valid_type?(type)
64
73
  DEFAULT_TYPES.include?(type.to_s) ||
74
+ !defined?(ActiveRecord::Base) ||
65
75
  ActiveRecord::Base.connection.valid_type?(type)
66
76
  end
67
77
 
@@ -78,6 +88,8 @@ module Rails
78
88
  # when declaring options curly brackets should be used
79
89
  def parse_type_and_options(type)
80
90
  case type
91
+ when /(text|binary)\{([a-z]+)\}/
92
+ return $1, size: $2.to_sym
81
93
  when /(string|text|binary|integer)\{(\d+)\}/
82
94
  return $1, limit: $2.to_i
83
95
  when /decimal\{(\d+)[,.-](\d+)\}/
@@ -57,13 +57,12 @@ module Rails
57
57
  source = File.expand_path(find_in_source_paths(source.to_s))
58
58
 
59
59
  set_migration_assigns!(destination)
60
- context = instance_eval("binding")
61
60
 
62
61
  dir, base = File.split(destination)
63
62
  numbered_destination = File.join(dir, ["%migration_number%", base].join("_"))
64
63
 
65
64
  file = create_migration numbered_destination, nil, config do
66
- ERB.new(::File.binread(source), trim_mode: "-", eoutvar: "@output_buffer").result(context)
65
+ ERB.new(::File.binread(source), trim_mode: "-", eoutvar: "@output_buffer").result(binding)
67
66
  end
68
67
  Rails::Generators.add_generated_file(file)
69
68
  end
@@ -19,7 +19,8 @@ module Rails
19
19
  mattr_accessor :skip_warn
20
20
 
21
21
  def self.included(base) # :nodoc:
22
- base.class_option :force_plural, type: :boolean, default: false, desc: "Forces the use of the given model name"
22
+ base.class_option :force_plural, type: :boolean, default: false,
23
+ desc: "Do not singularize the model name, even if it appears plural"
23
24
  end
24
25
 
25
26
  def initialize(args, *_options)
@@ -1,15 +1,31 @@
1
1
  Description:
2
- The 'rails new' command creates a new Rails application with a default
2
+ The `rails new` command creates a new Rails application with a default
3
3
  directory structure and configuration at the path you specify.
4
4
 
5
5
  You can specify extra command-line arguments to be used every time
6
- 'rails new' runs in the .railsrc configuration file in your home directory,
6
+ `rails new` runs in the .railsrc configuration file in your home directory,
7
7
  or in $XDG_CONFIG_HOME/rails/railsrc if XDG_CONFIG_HOME is set.
8
8
 
9
9
  Note that the arguments specified in the .railsrc file don't affect the
10
- defaults values shown above in this help message.
10
+ default values shown above in this help message.
11
11
 
12
- Example:
13
- rails new ~/Code/Ruby/weblog
12
+ You can specify which version to use when creating a new rails application
13
+ using `rails _<version>_ new`.
14
14
 
15
- This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
15
+ Examples:
16
+ `rails new ~/Code/Ruby/weblog`
17
+
18
+ This generates a new Rails app in ~/Code/Ruby/weblog.
19
+
20
+ `rails _<version>_ new weblog`
21
+
22
+ This generates a new Rails app with the provided version in ./weblog.
23
+
24
+ `rails new weblog --api`
25
+
26
+ This generates a new Rails app in API mode in ./weblog.
27
+
28
+ `rails new weblog --skip-action-mailer`
29
+
30
+ This generates a new Rails app without Action Mailer in ./weblog.
31
+ Any part of Rails can be skipped during app generation.
@@ -21,8 +21,8 @@ module Rails
21
21
  RUBY
22
22
  end
23
23
 
24
- def method_missing(meth, *args, &block)
25
- @generator.send(meth, *args, &block)
24
+ def method_missing(...)
25
+ @generator.send(...)
26
26
  end
27
27
  end
28
28
 
@@ -54,6 +54,10 @@ module Rails
54
54
  template "ruby-version", ".ruby-version"
55
55
  end
56
56
 
57
+ def node_version
58
+ template "node-version", ".node-version"
59
+ end
60
+
57
61
  def gemfile
58
62
  template "Gemfile"
59
63
  end
@@ -70,12 +74,17 @@ module Rails
70
74
  template "gitattributes", ".gitattributes"
71
75
  end
72
76
 
77
+ def dockerfiles
78
+ template "Dockerfile"
79
+ template "dockerignore", ".dockerignore"
80
+
81
+ template "docker-entrypoint", "bin/docker-entrypoint"
82
+ chmod "bin/docker-entrypoint", 0755 & ~File.umask, verbose: false
83
+ end
84
+
73
85
  def version_control
74
86
  if !options[:skip_git] && !options[:pretend]
75
- run "git init", capture: options[:quiet], abort_on_failure: false
76
- if user_default_branch.strip.empty?
77
- `git symbolic-ref HEAD refs/heads/main`
78
- end
87
+ run git_init_command, capture: options[:quiet], abort_on_failure: false
79
88
  end
80
89
  end
81
90
 
@@ -103,16 +112,16 @@ module Rails
103
112
  empty_directory "config"
104
113
 
105
114
  inside "config" do
106
- template "routes.rb" unless options[:updating]
115
+ template "routes.rb" unless options[:update]
107
116
  template "application.rb"
108
117
  template "environment.rb"
109
- template "cable.yml" unless options[:updating] || options[:skip_action_cable]
110
- template "puma.rb" unless options[:updating]
111
- template "storage.yml" unless options[:updating] || skip_active_storage?
118
+ template "cable.yml" unless options[:update] || options[:skip_action_cable]
119
+ template "puma.rb" unless options[:update]
120
+ template "storage.yml" unless options[:update] || skip_active_storage?
112
121
 
113
122
  directory "environments"
114
123
  directory "initializers"
115
- directory "locales" unless options[:updating]
124
+ directory "locales" unless options[:update]
116
125
  end
117
126
  end
118
127
 
@@ -163,10 +172,6 @@ module Rails
163
172
  remove_file "config/initializers/permissions_policy.rb"
164
173
  end
165
174
  end
166
-
167
- if !skip_sprockets?
168
- insert_into_file "config/application.rb", %(require "sprockets/railtie"), after: /require\(["']rails\/all["']\)\n/
169
- end
170
175
  end
171
176
 
172
177
  def master_key
@@ -182,7 +187,15 @@ module Rails
182
187
  return if options[:pretend] || options[:dummy_app]
183
188
 
184
189
  require "rails/generators/rails/credentials/credentials_generator"
185
- Rails::Generators::CredentialsGenerator.new([], quiet: options[:quiet]).add_credentials_file_silently
190
+ Rails::Generators::CredentialsGenerator.new([], quiet: true).add_credentials_file
191
+ end
192
+
193
+ def credentials_diff_enroll
194
+ return if options[:skip_decrypted_diffs] || options[:dummy_app] || options[:pretend]
195
+
196
+ @generator.shell.mute do
197
+ rails_command "credentials:diff --enroll", inline: true, shell: @generator.shell
198
+ end
186
199
  end
187
200
 
188
201
  def database_yml
@@ -193,14 +206,6 @@ module Rails
193
206
  directory "db"
194
207
  end
195
208
 
196
- def db_when_updating
197
- path = File.expand_path("db/schema.rb", destination_root)
198
-
199
- if File.exist?(path)
200
- gsub_file("db/schema.rb", /ActiveRecord::Schema\.define/, "ActiveRecord::Schema[6.1].define")
201
- end
202
- end
203
-
204
209
  def lib
205
210
  empty_directory "lib"
206
211
  empty_directory_with_keep_file "lib/tasks"
@@ -252,11 +257,6 @@ module Rails
252
257
  def config_target_version
253
258
  defined?(@config_target_version) ? @config_target_version : Rails::VERSION::STRING.to_f
254
259
  end
255
-
256
- private
257
- def user_default_branch
258
- @user_default_branch ||= `git config init.defaultbranch`
259
- end
260
260
  end
261
261
 
262
262
  module Generators
@@ -273,42 +273,59 @@ module Rails
273
273
  class_option :version, type: :boolean, aliases: "-v", group: :rails, desc: "Show Rails version number and quit"
274
274
  class_option :api, type: :boolean, desc: "Preconfigure smaller stack for API only apps"
275
275
  class_option :minimal, type: :boolean, desc: "Preconfigure a minimal rails app"
276
- class_option :javascript, type: :string, aliases: "-j", default: "importmap", desc: "Choose JavaScript approach [options: importmap (default), webpack, esbuild, rollup]"
277
- class_option :css, type: :string, aliases: "-c", desc: "Choose CSS processor [options: tailwind, bootstrap, bulma, postcss, sass] check https://github.com/rails/cssbundling-rails"
278
- class_option :skip_bundle, type: :boolean, aliases: "-B", default: false, desc: "Don't run bundle install"
276
+ class_option :javascript, type: :string, aliases: ["-j", "--js"], default: "importmap", desc: "Choose JavaScript approach [options: importmap (default), bun, webpack, esbuild, rollup]"
277
+ class_option :css, type: :string, aliases: "-c", desc: "Choose CSS processor [options: tailwind, bootstrap, bulma, postcss, sass] check https://github.com/rails/cssbundling-rails for more options"
278
+ class_option :skip_bundle, type: :boolean, aliases: "-B", default: nil, desc: "Don't run bundle install"
279
+ class_option :skip_decrypted_diffs, type: :boolean, default: nil, desc: "Don't configure git to show decrypted diffs of encrypted credentials"
280
+
281
+ OPTION_IMPLICATIONS = # :nodoc:
282
+ AppBase::OPTION_IMPLICATIONS.merge(
283
+ skip_git: [:skip_decrypted_diffs],
284
+ minimal: [
285
+ :skip_action_cable,
286
+ :skip_action_mailbox,
287
+ :skip_action_mailer,
288
+ :skip_action_text,
289
+ :skip_active_job,
290
+ :skip_active_storage,
291
+ :skip_bootsnap,
292
+ :skip_dev_gems,
293
+ :skip_hotwire,
294
+ :skip_javascript,
295
+ :skip_jbuilder,
296
+ :skip_system_test,
297
+ ],
298
+ api: [
299
+ :skip_asset_pipeline,
300
+ :skip_javascript,
301
+ ],
302
+ ) do |option, implications, more_implications|
303
+ implications + more_implications
304
+ end
305
+
306
+ META_OPTIONS = [:minimal] # :nodoc:
307
+
308
+ def self.apply_rails_template(template, destination) # :nodoc:
309
+ generator = new([destination], { template: template }, { destination_root: destination })
310
+ generator.set_default_accessors!
311
+ generator.apply_rails_template
312
+ generator.run_bundle
313
+ generator.run_after_bundle_callbacks
314
+ end
279
315
 
280
316
  def initialize(*args)
281
317
  super
282
318
 
319
+ imply_options(OPTION_IMPLICATIONS, meta_options: META_OPTIONS)
320
+
283
321
  if !options[:skip_active_record] && !DATABASES.include?(options[:database])
284
322
  raise Error, "Invalid value for --database option. Supported preconfigurations are: #{DATABASES.join(", ")}."
285
323
  end
286
324
 
287
- # Force sprockets and JavaScript to be skipped when generating API only apps.
288
- # Can't modify options hash as it's frozen by default.
289
- if options[:api]
290
- self.options = options.merge(skip_asset_pipeline: true, skip_javascript: true).freeze
291
- end
292
-
293
- if options[:minimal]
294
- self.options = options.merge(
295
- skip_action_cable: true,
296
- skip_action_mailer: true,
297
- skip_action_mailbox: true,
298
- skip_action_text: true,
299
- skip_active_job: true,
300
- skip_active_storage: true,
301
- skip_bootsnap: true,
302
- skip_dev_gems: true,
303
- skip_javascript: true,
304
- skip_jbuilder: true,
305
- skip_system_test: true,
306
- skip_hotwire: true).freeze
307
- end
308
-
309
325
  @after_bundle_callbacks = []
310
326
  end
311
327
 
328
+ public_task :report_implied_options
312
329
  public_task :set_default_accessors!
313
330
  public_task :create_root
314
331
  public_task :target_rails_prerelease
@@ -316,6 +333,7 @@ module Rails
316
333
  def create_root_files
317
334
  build(:readme)
318
335
  build(:rakefile)
336
+ build(:node_version) if using_node?
319
337
  build(:ruby_version)
320
338
  build(:configru)
321
339
 
@@ -341,11 +359,6 @@ module Rails
341
359
  end
342
360
  remove_task :update_bin_files
343
361
 
344
- def update_db_schema
345
- build(:db_when_updating)
346
- end
347
- remove_task :update_db_schema
348
-
349
362
  def update_active_storage
350
363
  unless skip_active_storage?
351
364
  rails_command "active_storage:update", inline: true
@@ -353,6 +366,11 @@ module Rails
353
366
  end
354
367
  remove_task :update_active_storage
355
368
 
369
+ def create_dockerfiles
370
+ return if options[:skip_docker] || options[:dummy_app]
371
+ build(:dockerfiles)
372
+ end
373
+
356
374
  def create_config_files
357
375
  build(:config)
358
376
  end
@@ -368,6 +386,7 @@ module Rails
368
386
 
369
387
  def create_credentials
370
388
  build(:credentials)
389
+ build(:credentials_diff_enroll)
371
390
  end
372
391
 
373
392
  def display_upgrade_guide_info
@@ -418,7 +437,7 @@ module Rails
418
437
  end
419
438
 
420
439
  def create_storage_files
421
- build(:storage) unless skip_active_storage?
440
+ build(:storage)
422
441
  end
423
442
 
424
443
  def delete_app_assets_if_api_option
@@ -438,7 +457,7 @@ module Rails
438
457
 
439
458
  def delete_app_views_if_api_option
440
459
  if options[:api]
441
- if skip_action_mailer?
460
+ if options[:skip_action_mailer]
442
461
  remove_dir "app/views"
443
462
  else
444
463
  remove_file "app/views/layouts/application.html.erb"
@@ -483,7 +502,7 @@ module Rails
483
502
  end
484
503
 
485
504
  def delete_action_mailer_files_skipping_action_mailer
486
- if skip_action_mailer?
505
+ if options[:skip_action_mailer]
487
506
  remove_file "app/views/layouts/mailer.html.erb"
488
507
  remove_file "app/views/layouts/mailer.text.erb"
489
508
  remove_dir "app/mailers"
@@ -514,7 +533,7 @@ module Rails
514
533
 
515
534
  def delete_new_framework_defaults
516
535
  unless options[:update]
517
- remove_file "config/initializers/new_framework_defaults_7_0.rb"
536
+ remove_file "config/initializers/new_framework_defaults_#{Rails::VERSION::MAJOR}_#{Rails::VERSION::MINOR}.rb"
518
537
  end
519
538
  end
520
539
 
@@ -522,7 +541,9 @@ module Rails
522
541
  build(:leftovers)
523
542
  end
524
543
 
525
- public_task :apply_rails_template, :run_bundle
544
+ public_task :apply_rails_template
545
+ public_task :run_bundle
546
+ public_task :add_bundler_platforms
526
547
  public_task :generate_bundler_binstub
527
548
  public_task :run_javascript
528
549
  public_task :run_hotwire
@@ -0,0 +1,103 @@
1
+ # syntax = docker/dockerfile:1
2
+
3
+ # Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
4
+ ARG RUBY_VERSION=<%= gem_ruby_version %>
5
+ FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
6
+
7
+ # Rails app lives here
8
+ WORKDIR /rails
9
+
10
+ # Set production environment
11
+ ENV RAILS_ENV="production" \
12
+ BUNDLE_DEPLOYMENT="1" \
13
+ BUNDLE_PATH="/usr/local/bundle" \
14
+ BUNDLE_WITHOUT="development"
15
+
16
+
17
+ # Throw-away build stage to reduce size of final image
18
+ FROM base as build
19
+
20
+ # Install packages needed to build gems<%= using_node? ? " and node modules" : "" %>
21
+ RUN apt-get update -qq && \
22
+ apt-get install --no-install-recommends -y <%= dockerfile_build_packages.join(" ") %>
23
+
24
+ <% if using_node? -%>
25
+ # Install JavaScript dependencies
26
+ ARG NODE_VERSION=<%= node_version %>
27
+ ARG YARN_VERSION=<%= dockerfile_yarn_version %>
28
+ ENV PATH=/usr/local/node/bin:$PATH
29
+ RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
30
+ /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
31
+ npm install -g yarn@$YARN_VERSION && \
32
+ rm -rf /tmp/node-build-master
33
+
34
+ <% end -%>
35
+ <% if using_bun? -%>
36
+ ENV BUN_INSTALL=/usr/local/bun
37
+ ENV PATH=/usr/local/bun/bin:$PATH
38
+ ARG BUN_VERSION=<%= dockerfile_bun_version %>
39
+ RUN curl -fsSL https://bun.sh/install | bash -s -- "bun-v${BUN_VERSION}"
40
+
41
+ <% end -%>
42
+ # Install application gems
43
+ COPY Gemfile Gemfile.lock ./
44
+ RUN bundle install && \
45
+ rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git<% if depend_on_bootsnap? -%> && \
46
+ bundle exec bootsnap precompile --gemfile<% end %>
47
+
48
+ <% if using_node? -%>
49
+ # Install node modules
50
+ COPY package.json yarn.lock ./
51
+ RUN yarn install --frozen-lockfile
52
+
53
+ <% end -%>
54
+ <% if using_bun? -%>
55
+ # Install node modules
56
+ COPY package.json bun.lockb ./
57
+ RUN bun install --frozen-lockfile
58
+
59
+ <% end -%>
60
+ # Copy application code
61
+ COPY . .
62
+
63
+ <% if depend_on_bootsnap? -%>
64
+ # Precompile bootsnap code for faster boot times
65
+ RUN bundle exec bootsnap precompile app/ lib/
66
+
67
+ <% end -%>
68
+ <% unless dockerfile_binfile_fixups.empty? -%>
69
+ # Adjust binfiles to be executable on Linux
70
+ <%= "RUN " + dockerfile_binfile_fixups.join(" && \\\n ") %>
71
+
72
+ <% end -%>
73
+ <% unless options.api? || skip_asset_pipeline? -%>
74
+ # Precompiling assets for production without requiring secret RAILS_MASTER_KEY
75
+ RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
76
+
77
+ <% end -%>
78
+
79
+ # Final stage for app image
80
+ FROM base
81
+
82
+ <% unless dockerfile_deploy_packages.empty? -%>
83
+ # Install packages needed for deployment
84
+ RUN apt-get update -qq && \
85
+ apt-get install --no-install-recommends -y <%= dockerfile_deploy_packages.join(" ") %> && \
86
+ rm -rf /var/lib/apt/lists /var/cache/apt/archives
87
+
88
+ <% end -%>
89
+ # Copy built artifacts: gems, application
90
+ COPY --from=build /usr/local/bundle /usr/local/bundle
91
+ COPY --from=build /rails /rails
92
+
93
+ # Run and own only the runtime files as a non-root user for security
94
+ RUN useradd rails --create-home --shell /bin/bash && \
95
+ chown -R rails:rails <%= dockerfile_chown_directories.join(" ") %>
96
+ USER rails:rails
97
+
98
+ # Entrypoint prepares the database.
99
+ ENTRYPOINT ["/rails/bin/docker-entrypoint"]
100
+
101
+ # Start the server by default, this can be overwritten at runtime
102
+ EXPOSE 3000
103
+ CMD ["./bin/rails", "server"]