railties 7.0.8.7 → 7.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +210 -272
  3. data/MIT-LICENSE +1 -1
  4. data/RDOC_MAIN.md +99 -0
  5. data/README.rdoc +4 -4
  6. data/lib/minitest/rails_plugin.rb +67 -1
  7. data/lib/rails/all.rb +1 -3
  8. data/lib/rails/api/task.rb +39 -6
  9. data/lib/rails/application/bootstrap.rb +28 -10
  10. data/lib/rails/application/configuration.rb +228 -72
  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 +50 -33
  14. data/lib/rails/application.rb +117 -76
  15. data/lib/rails/backtrace_cleaner.rb +19 -4
  16. data/lib/rails/cli.rb +5 -3
  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/app/update_command.rb +102 -0
  24. data/lib/rails/commands/application/application_command.rb +2 -0
  25. data/lib/rails/commands/boot/boot_command.rb +14 -0
  26. data/lib/rails/commands/console/console_command.rb +11 -30
  27. data/lib/rails/commands/console/irb_console.rb +146 -0
  28. data/lib/rails/commands/credentials/USAGE +53 -55
  29. data/lib/rails/commands/credentials/credentials_command/diffing.rb +5 -3
  30. data/lib/rails/commands/credentials/credentials_command.rb +64 -70
  31. data/lib/rails/commands/db/system/change/change_command.rb +2 -1
  32. data/lib/rails/commands/dbconsole/dbconsole_command.rb +32 -131
  33. data/lib/rails/commands/destroy/destroy_command.rb +3 -2
  34. data/lib/rails/commands/dev/dev_command.rb +1 -6
  35. data/lib/rails/commands/devcontainer/devcontainer_command.rb +39 -0
  36. data/lib/rails/commands/encrypted/USAGE +15 -20
  37. data/lib/rails/commands/encrypted/encrypted_command.rb +46 -35
  38. data/lib/rails/commands/gem_help/USAGE +16 -0
  39. data/lib/rails/commands/gem_help/gem_help_command.rb +13 -0
  40. data/lib/rails/commands/generate/generate_command.rb +2 -2
  41. data/lib/rails/commands/help/USAGE +13 -13
  42. data/lib/rails/commands/help/help_command.rb +21 -2
  43. data/lib/rails/commands/initializers/initializers_command.rb +1 -4
  44. data/lib/rails/commands/middleware/middleware_command.rb +17 -0
  45. data/lib/rails/commands/new/new_command.rb +2 -0
  46. data/lib/rails/commands/notes/notes_command.rb +2 -1
  47. data/lib/rails/commands/plugin/plugin_command.rb +2 -0
  48. data/lib/rails/commands/rake/rake_command.rb +25 -22
  49. data/lib/rails/commands/restart/restart_command.rb +14 -0
  50. data/lib/rails/commands/routes/routes_command.rb +13 -1
  51. data/lib/rails/commands/runner/USAGE +14 -12
  52. data/lib/rails/commands/runner/runner_command.rb +42 -19
  53. data/lib/rails/commands/secret/secret_command.rb +13 -0
  54. data/lib/rails/commands/server/server_command.rb +37 -34
  55. data/lib/rails/commands/test/USAGE +14 -0
  56. data/lib/rails/commands/test/test_command.rb +58 -14
  57. data/lib/rails/commands/unused_routes/unused_routes_command.rb +75 -0
  58. data/lib/rails/commands/version/version_command.rb +1 -0
  59. data/lib/rails/configuration.rb +15 -6
  60. data/lib/rails/console/app.rb +5 -35
  61. data/lib/rails/console/helpers.rb +5 -16
  62. data/lib/rails/console/methods.rb +23 -0
  63. data/lib/rails/deprecator.rb +7 -0
  64. data/lib/rails/engine/configuration.rb +50 -6
  65. data/lib/rails/engine.rb +53 -25
  66. data/lib/rails/gem_version.rb +4 -4
  67. data/lib/rails/generators/actions.rb +6 -15
  68. data/lib/rails/generators/active_model.rb +28 -14
  69. data/lib/rails/generators/app_base.rb +382 -88
  70. data/lib/rails/generators/app_name.rb +3 -14
  71. data/lib/rails/generators/base.rb +21 -9
  72. data/lib/rails/generators/database.rb +231 -35
  73. data/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt +1 -1
  74. data/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt +2 -0
  75. data/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt +2 -0
  76. data/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt +2 -0
  77. data/lib/rails/generators/generated_attribute.rb +38 -1
  78. data/lib/rails/generators/migration.rb +4 -5
  79. data/lib/rails/generators/model_helpers.rb +2 -1
  80. data/lib/rails/generators/rails/app/USAGE +22 -6
  81. data/lib/rails/generators/rails/app/app_generator.rb +135 -86
  82. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +110 -0
  83. data/lib/rails/generators/rails/app/templates/Gemfile.tt +19 -21
  84. data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +4 -0
  85. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +8 -1
  86. data/lib/rails/generators/rails/app/templates/app/views/layouts/mailer.html.erb.tt +1 -1
  87. data/lib/rails/generators/rails/app/templates/app/views/pwa/manifest.json.erb.tt +22 -0
  88. data/lib/rails/generators/rails/app/templates/app/views/pwa/service-worker.js +26 -0
  89. data/lib/rails/generators/rails/app/templates/bin/brakeman.tt +6 -0
  90. data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +7 -0
  91. data/lib/rails/generators/rails/app/templates/bin/setup.tt +15 -2
  92. data/lib/rails/generators/rails/app/templates/config/application.rb.tt +6 -17
  93. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +3 -3
  94. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +11 -6
  95. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +10 -3
  96. data/lib/rails/generators/rails/app/templates/config/databases/{jdbcmysql.yml.tt → trilogy.yml.tt} +12 -7
  97. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +25 -8
  98. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +40 -28
  99. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +20 -13
  100. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +3 -1
  101. data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +2 -2
  102. data/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt +1 -1
  103. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +4 -4
  104. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +70 -0
  105. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +11 -9
  106. data/lib/rails/generators/rails/app/templates/config/locales/en.yml +11 -13
  107. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +25 -34
  108. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +11 -1
  109. data/lib/rails/generators/rails/app/templates/db/seeds.rb.tt +6 -4
  110. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +15 -0
  111. data/lib/rails/generators/rails/app/templates/dockerignore.tt +56 -0
  112. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +138 -0
  113. data/lib/rails/generators/rails/app/templates/github/dependabot.yml +12 -0
  114. data/lib/rails/generators/rails/app/templates/gitignore.tt +7 -11
  115. data/lib/rails/generators/rails/app/templates/node-version.tt +1 -0
  116. data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +66 -0
  117. data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
  118. data/lib/rails/generators/rails/app/templates/public/icon.svg +3 -0
  119. data/lib/rails/generators/rails/app/templates/rubocop.yml.tt +8 -0
  120. data/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt +1 -1
  121. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +10 -8
  122. data/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +9 -7
  123. data/lib/rails/generators/rails/application_record/application_record_generator.rb +4 -0
  124. data/lib/rails/generators/rails/benchmark/benchmark_generator.rb +2 -1
  125. data/lib/rails/generators/rails/controller/USAGE +12 -4
  126. data/lib/rails/generators/rails/controller/controller_generator.rb +6 -1
  127. data/lib/rails/generators/rails/controller/templates/controller.rb.tt +1 -1
  128. data/lib/rails/generators/rails/credentials/credentials_generator.rb +29 -24
  129. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +8 -0
  130. data/lib/rails/generators/rails/db/system/change/change_generator.rb +146 -5
  131. data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +166 -0
  132. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +3 -0
  133. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/compose.yaml.tt +47 -0
  134. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +37 -0
  135. data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +1 -2
  136. data/lib/rails/generators/rails/migration/USAGE +21 -11
  137. data/lib/rails/generators/rails/migration/migration_generator.rb +4 -0
  138. data/lib/rails/generators/rails/model/model_generator.rb +4 -0
  139. data/lib/rails/generators/rails/plugin/USAGE +17 -6
  140. data/lib/rails/generators/rails/plugin/plugin_generator.rb +45 -22
  141. data/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt +2 -2
  142. data/lib/rails/generators/rails/plugin/templates/Gemfile.tt +7 -3
  143. data/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt +1 -1
  144. data/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +2 -0
  145. data/lib/rails/generators/rails/plugin/templates/bin/rails.tt +1 -17
  146. data/lib/rails/generators/rails/plugin/templates/bin/rubocop.tt +7 -0
  147. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +103 -0
  148. data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +12 -0
  149. data/lib/rails/generators/rails/plugin/templates/gitignore.tt +0 -2
  150. data/lib/rails/generators/rails/plugin/templates/rubocop.yml.tt +8 -0
  151. data/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt +1 -1
  152. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +5 -5
  153. data/lib/rails/generators/rails/resource/resource_generator.rb +6 -0
  154. data/lib/rails/generators/rails/scaffold/scaffold_generator.rb +2 -1
  155. data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +1 -1
  156. data/lib/rails/generators/test_case.rb +2 -2
  157. data/lib/rails/generators/test_unit/mailer/templates/functional_test.rb.tt +6 -4
  158. data/lib/rails/generators/test_unit/mailer/templates/preview.rb.tt +3 -2
  159. data/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +16 -2
  160. data/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt +2 -2
  161. data/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt +2 -2
  162. data/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt +2 -0
  163. data/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt +1 -1
  164. data/lib/rails/generators/testing/assertions.rb +20 -0
  165. data/lib/rails/generators/testing/{behaviour.rb → behavior.rb} +8 -4
  166. data/lib/rails/generators.rb +12 -16
  167. data/lib/rails/health_controller.rb +55 -0
  168. data/lib/rails/info.rb +3 -3
  169. data/lib/rails/info_controller.rb +33 -11
  170. data/lib/rails/mailers_controller.rb +29 -6
  171. data/lib/rails/paths.rb +15 -12
  172. data/lib/rails/pwa_controller.rb +15 -0
  173. data/lib/rails/rack/logger.rb +27 -16
  174. data/lib/rails/rackup/server.rb +15 -0
  175. data/lib/rails/railtie/configurable.rb +2 -2
  176. data/lib/rails/railtie/configuration.rb +14 -1
  177. data/lib/rails/railtie.rb +33 -34
  178. data/lib/rails/source_annotation_extractor.rb +67 -18
  179. data/lib/rails/tasks/engine.rake +8 -8
  180. data/lib/rails/tasks/framework.rake +2 -34
  181. data/lib/rails/tasks/log.rake +1 -1
  182. data/lib/rails/tasks/misc.rake +3 -14
  183. data/lib/rails/tasks/statistics.rake +5 -4
  184. data/lib/rails/tasks/tmp.rake +6 -6
  185. data/lib/rails/tasks/zeitwerk.rake +15 -35
  186. data/lib/rails/tasks.rb +0 -2
  187. data/lib/rails/templates/layouts/application.html.erb +1 -1
  188. data/lib/rails/templates/rails/mailers/email.html.erb +44 -8
  189. data/lib/rails/templates/rails/mailers/index.html.erb +14 -7
  190. data/lib/rails/templates/rails/mailers/mailer.html.erb +11 -5
  191. data/lib/rails/templates/rails/welcome/index.html.erb +5 -2
  192. data/lib/rails/test_help.rb +11 -18
  193. data/lib/rails/test_unit/line_filtering.rb +1 -1
  194. data/lib/rails/test_unit/reporter.rb +14 -4
  195. data/lib/rails/test_unit/runner.rb +62 -20
  196. data/lib/rails/test_unit/test_parser.rb +133 -0
  197. data/lib/rails/test_unit/testing.rake +13 -33
  198. data/lib/rails/testing/maintain_test_schema.rb +16 -0
  199. data/lib/rails/version.rb +1 -1
  200. data/lib/rails/zeitwerk_checker.rb +15 -0
  201. data/lib/rails.rb +20 -17
  202. metadata +87 -40
  203. data/RDOC_MAIN.rdoc +0 -97
  204. data/lib/rails/app_updater.rb +0 -40
  205. data/lib/rails/application/dummy_erb_compiler.rb +0 -18
  206. data/lib/rails/commands/secrets/USAGE +0 -66
  207. data/lib/rails/commands/secrets/secrets_command.rb +0 -65
  208. data/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt +0 -68
  209. data/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt +0 -70
  210. data/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +0 -24
  211. data/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt +0 -62
  212. data/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt +0 -53
  213. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt +0 -143
  214. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon-precomposed.png +0 -0
  215. data/lib/rails/generators/rails/app/templates/public/apple-touch-icon.png +0 -0
  216. data/lib/rails/generators/rails/app/templates/public/favicon.ico +0 -0
  217. data/lib/rails/generators/rails/model/USAGE +0 -113
  218. data/lib/rails/ruby_version_check.rb +0 -15
  219. data/lib/rails/secrets.rb +0 -110
  220. data/lib/rails/tasks/middleware.rake +0 -9
  221. data/lib/rails/tasks/restart.rake +0 -9
@@ -1,20 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "irb"
4
- require "irb/completion"
5
-
6
3
  require "rails/command/environment_argument"
7
4
 
8
5
  module Rails
9
6
  class Console
10
- module BacktraceCleaner
11
- def filter_backtrace(bt)
12
- if result = super
13
- Rails.backtrace_cleaner.filter([result]).first
14
- end
15
- end
16
- end
17
-
18
7
  def self.start(*args)
19
8
  new(*args).start
20
9
  end
@@ -34,19 +23,18 @@ module Rails
34
23
 
35
24
  app.load_console
36
25
 
37
- @console = app.config.console || IRB
38
-
39
- if @console == IRB
40
- IRB::WorkSpace.prepend(BacktraceCleaner)
41
-
42
- if Rails.env.production?
43
- ENV["IRB_USE_AUTOCOMPLETE"] ||= "false"
44
- end
26
+ @console = app.config.console || begin
27
+ require "rails/commands/console/irb_console"
28
+ IRBConsole.new(app)
45
29
  end
46
30
  end
47
31
 
48
32
  def sandbox?
49
- options[:sandbox]
33
+ return options[:sandbox] if !options[:sandbox].nil?
34
+
35
+ return false if Rails.env.local?
36
+
37
+ app.config.sandbox_by_default
50
38
  end
51
39
 
52
40
  def environment
@@ -68,9 +56,6 @@ module Rails
68
56
  puts "Loading #{Rails.env} environment (Rails #{Rails.version})"
69
57
  end
70
58
 
71
- if defined?(console::ExtendCommandBundle)
72
- console::ExtendCommandBundle.include(Rails::ConsoleMethods)
73
- end
74
59
  console.start
75
60
  end
76
61
  end
@@ -79,7 +64,7 @@ module Rails
79
64
  class ConsoleCommand < Base # :nodoc:
80
65
  include EnvironmentArgument
81
66
 
82
- class_option :sandbox, aliases: "-s", type: :boolean, default: false,
67
+ class_option :sandbox, aliases: "-s", type: :boolean, default: nil,
83
68
  desc: "Rollback database modifications on exit."
84
69
 
85
70
  def initialize(args = [], local_options = {}, config = {})
@@ -96,13 +81,9 @@ module Rails
96
81
  super(args, local_options, config)
97
82
  end
98
83
 
84
+ desc "console", "Start the Rails console"
99
85
  def perform
100
- extract_environment_option_from_argument
101
-
102
- # RAILS_ENV needs to be set before config/application is required.
103
- ENV["RAILS_ENV"] = options[:environment]
104
-
105
- require_application_and_environment!
86
+ boot_application!
106
87
  Rails::Console.start(Rails.application, options)
107
88
  end
108
89
  end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "irb/helper_method"
4
+ require "irb/command"
5
+
6
+ module Rails
7
+ class Console
8
+ class RailsHelperBase < IRB::HelperMethod::Base
9
+ include ConsoleMethods
10
+ end
11
+
12
+ class ControllerHelper < RailsHelperBase
13
+ description "Gets helper methods available to ApplicationController."
14
+
15
+ # This method assumes an +ApplicationController+ exists, and that it extends ActionController::Base.
16
+ def execute
17
+ ApplicationController.helpers
18
+ end
19
+ end
20
+
21
+ class ControllerInstance < RailsHelperBase
22
+ description "Gets a new instance of ApplicationController."
23
+
24
+ # This method assumes an +ApplicationController+ exists, and that it extends ActionController::Base.
25
+ def execute
26
+ @controller ||= ApplicationController.new
27
+ end
28
+ end
29
+
30
+ class NewSession < RailsHelperBase
31
+ description "[Deprecated] Please use `app(true)` instead."
32
+
33
+ def execute(*)
34
+ app = Rails.application
35
+ session = ActionDispatch::Integration::Session.new(app)
36
+
37
+ # This makes app.url_for and app.foo_path available in the console
38
+ session.extend(app.routes.url_helpers)
39
+ session.extend(app.routes.mounted_helpers)
40
+
41
+ session
42
+ end
43
+ end
44
+
45
+ class AppInstance < NewSession
46
+ description "Creates a new ActionDispatch::Integration::Session and memoizes it. Use `app(true)` to create a new instance."
47
+
48
+ def execute(create = false)
49
+ @app_integration_instance = nil if create
50
+ @app_integration_instance ||= super
51
+ end
52
+ end
53
+
54
+ class ReloadHelper < RailsHelperBase
55
+ description "Reloads the Rails application."
56
+
57
+ def execute
58
+ puts "Reloading..."
59
+ Rails.application.reloader.reload!
60
+ end
61
+ end
62
+
63
+ class ReloadCommand < IRB::Command::Base
64
+ include ConsoleMethods
65
+
66
+ category "Rails console"
67
+ description "Reloads the Rails application."
68
+
69
+ def execute(*)
70
+ puts "Reloading..."
71
+ Rails.application.reloader.reload!
72
+ end
73
+ end
74
+
75
+ IRB::HelperMethod.register(:helper, ControllerHelper)
76
+ IRB::HelperMethod.register(:controller, ControllerInstance)
77
+ IRB::HelperMethod.register(:new_session, NewSession)
78
+ IRB::HelperMethod.register(:app, AppInstance)
79
+ IRB::HelperMethod.register(:reload!, ReloadHelper)
80
+ IRB::Command.register(:reload!, ReloadCommand)
81
+
82
+ class IRBConsole
83
+ def initialize(app)
84
+ @app = app
85
+
86
+ require "irb"
87
+ require "irb/completion"
88
+ end
89
+
90
+ def name
91
+ "IRB"
92
+ end
93
+
94
+ def start
95
+ IRB.setup(nil)
96
+
97
+ if !Rails.env.local? && !ENV.key?("IRB_USE_AUTOCOMPLETE")
98
+ IRB.conf[:USE_AUTOCOMPLETE] = false
99
+ end
100
+
101
+ env = colorized_env
102
+ prompt_prefix = "%N(#{env})"
103
+ IRB.conf[:IRB_NAME] = @app.name
104
+
105
+ IRB.conf[:PROMPT][:RAILS_PROMPT] = {
106
+ PROMPT_I: "#{prompt_prefix}> ",
107
+ PROMPT_S: "#{prompt_prefix}%l ",
108
+ PROMPT_C: "#{prompt_prefix}* ",
109
+ RETURN: "=> %s\n"
110
+ }
111
+
112
+ if current_filter = IRB.conf[:BACKTRACE_FILTER]
113
+ IRB.conf[:BACKTRACE_FILTER] = -> (backtrace) do
114
+ backtrace = current_filter.call(backtrace)
115
+ Rails.backtrace_cleaner.filter(backtrace)
116
+ end
117
+ else
118
+ IRB.conf[:BACKTRACE_FILTER] = -> (backtrace) do
119
+ Rails.backtrace_cleaner.filter(backtrace)
120
+ end
121
+ end
122
+
123
+ # Because some users/libs use Rails::ConsoleMethods to extend Rails console,
124
+ # we still include it for backward compatibility.
125
+ IRB::ExtendCommandBundle.include ConsoleMethods
126
+
127
+ # Respect user's choice of prompt mode.
128
+ IRB.conf[:PROMPT_MODE] = :RAILS_PROMPT if IRB.conf[:PROMPT_MODE] == :DEFAULT
129
+ IRB::Irb.new.run(IRB.conf)
130
+ end
131
+
132
+ def colorized_env
133
+ case Rails.env
134
+ when "development"
135
+ IRB::Color.colorize("dev", [:BLUE])
136
+ when "test"
137
+ IRB::Color.colorize("test", [:BLUE])
138
+ when "production"
139
+ IRB::Color.colorize("prod", [:RED])
140
+ else
141
+ Rails.env
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -1,75 +1,73 @@
1
- === Storing Encrypted Credentials in Source Control
1
+ Description:
2
+ The Rails `credentials` commands provide access to encrypted credentials,
3
+ so you can safely store access tokens, database passwords, and the like
4
+ safely inside the app without relying on a mess of ENVs.
2
5
 
3
- The Rails `credentials` commands provide access to encrypted credentials,
4
- so you can safely store access tokens, database passwords, and the like
5
- safely inside the app without relying on a mess of ENVs.
6
+ This also allows for atomic deploys: no need to coordinate key changes
7
+ to get everything working as the keys are shipped with the code.
6
8
 
7
- This also allows for atomic deploys: no need to coordinate key changes
8
- to get everything working as the keys are shipped with the code.
9
+ Setup:
10
+ Applications after Rails 5.2 automatically have a basic credentials file generated
11
+ that just contains the secret_key_base used by MessageVerifiers/MessageEncryptors, like the ones
12
+ signing and encrypting cookies.
9
13
 
10
- === Setup
14
+ For applications created prior to Rails 5.2, we'll automatically generate a new
15
+ credentials file in `config/credentials.yml.enc` the first time you run `<%= executable(:edit) %>`.
16
+ If you didn't have a master key saved in `config/master.key`, that'll be created too.
11
17
 
12
- Applications after Rails 5.2 automatically have a basic credentials file generated
13
- that just contains the secret_key_base used by MessageVerifiers/MessageEncryptors, like the ones
14
- signing and encrypting cookies.
18
+ Don't lose this master key! Put it in a password manager your team can access.
19
+ Should you lose it no one, including you, will be able to access any encrypted
20
+ credentials.
15
21
 
16
- For applications created prior to Rails 5.2, we'll automatically generate a new
17
- credentials file in `config/credentials.yml.enc` the first time you run `bin/rails credentials:edit`.
18
- If you didn't have a master key saved in `config/master.key`, that'll be created too.
22
+ Don't commit the key! Add `config/master.key` to your source control's
23
+ ignore file. If you use Git, Rails handles this for you.
19
24
 
20
- Don't lose this master key! Put it in a password manager your team can access.
21
- Should you lose it no one, including you, will be able to access any encrypted
22
- credentials.
25
+ Rails also looks for the master key in `ENV["RAILS_MASTER_KEY"]`, in case that
26
+ is easier to manage. You could set `RAILS_MASTER_KEY` in a deployment
27
+ configuration, or you could prepend it to your server's start command like so:
23
28
 
24
- Don't commit the key! Add `config/master.key` to your source control's
25
- ignore file. If you use Git, Rails handles this for you.
29
+ RAILS_MASTER_KEY="very-secret-and-secure" bin/rails server
26
30
 
27
- Rails also looks for the master key in `ENV["RAILS_MASTER_KEY"]`, if that's easier to manage.
31
+ If `ENV["RAILS_MASTER_KEY"]` is present, it takes precedence over
32
+ `config/master.key`.
28
33
 
29
- You could prepend that to your server's start command like this:
34
+ Set up Git to Diff Credentials:
35
+ Rails provides `<%= executable(:diff) %> --enroll` to instruct Git to call
36
+ `<%= executable(:diff) %>` when `git diff` is run on a credentials file.
30
37
 
31
- RAILS_MASTER_KEY="very-secret-and-secure" server.start
38
+ Running the command enrolls the project such that all credentials files use the
39
+ "rails_credentials" diff driver in .gitattributes.
32
40
 
33
- === Set up Git to Diff Credentials
41
+ Additionally since Git requires the driver itself to be set up in a config file
42
+ that isn't tracked Rails automatically ensures it's configured when running
43
+ `<%= executable(:edit) %>`.
34
44
 
35
- Rails provides `bin/rails credentials:diff --enroll` to instruct Git to call
36
- `bin/rails credentials:diff` when `git diff` is run on a credentials file.
45
+ Otherwise each co-worker would have to run enable manually, including on each new
46
+ repo clone.
37
47
 
38
- Running the command enrolls the project such that all credentials files use the
39
- "rails_credentials" diff driver in .gitattributes.
48
+ To disenroll from this feature, run `<%= executable(:diff) %> --disenroll`.
40
49
 
41
- Additionally since Git requires the driver itself to be set up in a config file
42
- that isn't tracked Rails automatically ensures it's configured when running
43
- `credentials:edit`.
50
+ Editing Credentials:
51
+ This will open a temporary file in `$VISUAL` or `$EDITOR` with the decrypted
52
+ contents to edit the encrypted credentials.
44
53
 
45
- Otherwise each co-worker would have to run enable manually, including on each new
46
- repo clone.
54
+ When the temporary file is next saved the contents are encrypted and written to
55
+ `config/credentials.yml.enc` while the file itself is destroyed to prevent credentials
56
+ from leaking.
47
57
 
48
- To disenroll from this feature, run `bin/rails credentials:diff --disenroll`.
58
+ Environment Specific Credentials:
59
+ The `credentials` command supports passing an `--environment` option to create an
60
+ environment specific override. That override will take precedence over the
61
+ global `config/credentials.yml.enc` file when running in that environment. So:
49
62
 
50
- === Editing Credentials
63
+ <%= executable(:edit) %> --environment development
51
64
 
52
- This will open a temporary file in `$EDITOR` with the decrypted contents to edit
53
- the encrypted credentials.
65
+ will create `config/credentials/development.yml.enc` with the corresponding
66
+ encryption key in `config/credentials/development.key` if the credentials file
67
+ doesn't exist.
54
68
 
55
- When the temporary file is next saved the contents are encrypted and written to
56
- `config/credentials.yml.enc` while the file itself is destroyed to prevent credentials
57
- from leaking.
69
+ In addition to that, the default credentials lookup paths can be overridden through
70
+ `config.credentials.content_path` and `config.credentials.key_path`.
58
71
 
59
- === Environment Specific Credentials
60
-
61
- The `credentials` command supports passing an `--environment` option to create an
62
- environment specific override. That override will take precedence over the
63
- global `config/credentials.yml.enc` file when running in that environment. So:
64
-
65
- bin/rails credentials:edit --environment development
66
-
67
- will create `config/credentials/development.yml.enc` with the corresponding
68
- encryption key in `config/credentials/development.key` if the credentials file
69
- doesn't exist.
70
-
71
- The encryption key can also be put in `ENV["RAILS_MASTER_KEY"]`, which takes
72
- precedence over the file encryption key.
73
-
74
- In addition to that, the default credentials lookup paths can be overridden through
75
- `config.credentials.content_path` and `config.credentials.key_path`.
72
+ Just as with `config/master.key`, `ENV["RAILS_MASTER_KEY"]` takes precedence
73
+ over any environment specific or specially configured key files.
@@ -13,7 +13,8 @@ module Rails::Command::CredentialsCommand::Diffing # :nodoc:
13
13
  gitattributes.write(GITATTRIBUTES_ENTRY, mode: "a")
14
14
 
15
15
  say "Enrolled project in credentials file diffing!"
16
- say "Rails ensures the rails_credentials diff driver is set when running `credentials:edit`. See `credentials:help` for more."
16
+ say ""
17
+ say "Rails will configure the Git diff driver for credentials when running `#{executable(:edit)}`. See `#{executable(:help)}` for more information."
17
18
  end
18
19
  end
19
20
 
@@ -42,10 +43,11 @@ module Rails::Command::CredentialsCommand::Diffing # :nodoc:
42
43
  end
43
44
 
44
45
  def configure_diffing_driver
45
- system "git config diff.rails_credentials.textconv 'bin/rails credentials:diff'"
46
+ system "git config diff.rails_credentials.textconv '#{executable(:diff)}'"
47
+ say "Configured Git diff driver for credentials."
46
48
  end
47
49
 
48
50
  def gitattributes
49
- Rails.root.join(".gitattributes")
51
+ @gitattributes ||= (Rails::Command.root || Pathname.pwd).join(".gitattributes")
50
52
  end
51
53
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "pathname"
4
- require "shellwords"
5
4
  require "active_support"
6
5
  require "rails/command/helpers/editor"
7
6
  require "rails/command/environment_argument"
@@ -15,56 +14,42 @@ module Rails
15
14
  require_relative "credentials_command/diffing"
16
15
  include Diffing
17
16
 
18
- self.environment_desc = "Uses credentials from config/credentials/:environment.yml.enc encrypted by config/credentials/:environment.key key"
19
-
20
- no_commands do
21
- def help
22
- say "Usage:\n #{self.class.banner}"
23
- say ""
24
- say self.class.desc
25
- end
26
- end
27
-
17
+ desc "edit", "Open the decrypted credentials in `$VISUAL` or `$EDITOR` for editing"
28
18
  def edit
29
- extract_environment_option_from_argument(default_environment: nil)
30
- require_application!
19
+ load_environment_config!
20
+ load_generators
31
21
 
32
- ensure_editor_available(command: "bin/rails credentials:edit") || (return)
22
+ if environment_specified?
23
+ @content_path = "config/credentials/#{environment}.yml.enc" unless config.overridden?(:content_path)
24
+ @key_path = "config/credentials/#{environment}.key" unless config.overridden?(:key_path)
25
+ end
33
26
 
34
- ensure_encryption_key_has_been_added if credentials.key.nil?
27
+ ensure_encryption_key_has_been_added
35
28
  ensure_credentials_have_been_added
36
29
  ensure_diffing_driver_is_configured
37
30
 
38
- catch_editing_exceptions do
39
- change_credentials_in_system_editor
40
- end
41
-
42
- say "File encrypted and saved."
43
- rescue ActiveSupport::MessageEncryptor::InvalidMessage
44
- say "Couldn't decrypt #{content_path}. Perhaps you passed the wrong key?"
31
+ change_credentials_in_system_editor
45
32
  end
46
33
 
34
+ desc "show", "Show the decrypted credentials"
47
35
  def show
48
- extract_environment_option_from_argument(default_environment: nil)
49
- require_application!
36
+ load_environment_config!
50
37
 
51
38
  say credentials.read.presence || missing_credentials_message
52
39
  end
53
40
 
41
+ desc "diff", "Enroll/disenroll in decrypted diffs of credentials using git"
54
42
  option :enroll, type: :boolean, default: false,
55
- desc: "Enrolls project in credentials file diffing with `git diff`"
56
-
43
+ desc: "Enroll project in credentials file diffing with `git diff`"
57
44
  option :disenroll, type: :boolean, default: false,
58
- desc: "Disenrolls project from credentials file diffing"
59
-
45
+ desc: "Disenroll project from credentials file diffing"
60
46
  def diff(content_path = nil)
61
47
  if @content_path = content_path
62
- extract_environment_option_from_argument(default_environment: extract_environment_from_path(content_path))
63
- require_application!
48
+ self.environment = extract_environment_from_path(content_path)
49
+ load_environment_config!
64
50
 
65
51
  say credentials.read.presence || credentials.content_path.read
66
52
  else
67
- require_application!
68
53
  disenroll_project_from_credentials_diffing if options[:disenroll]
69
54
  enroll_project_in_credentials_diffing if options[:enroll]
70
55
  end
@@ -73,68 +58,77 @@ module Rails
73
58
  end
74
59
 
75
60
  private
61
+ def config
62
+ Rails.application.config.credentials
63
+ end
64
+
65
+ def content_path
66
+ @content_path ||= relative_path(config.content_path)
67
+ end
68
+
69
+ def key_path
70
+ @key_path ||= relative_path(config.key_path)
71
+ end
72
+
76
73
  def credentials
77
- Rails.application.encrypted(content_path, key_path: key_path)
74
+ @credentials ||= Rails.application.encrypted(content_path, key_path: key_path)
78
75
  end
79
76
 
80
77
  def ensure_encryption_key_has_been_added
78
+ return if credentials.key?
79
+
80
+ require "rails/generators/rails/encryption_key_file/encryption_key_file_generator"
81
+
82
+ encryption_key_file_generator = Rails::Generators::EncryptionKeyFileGenerator.new
81
83
  encryption_key_file_generator.add_key_file(key_path)
82
84
  encryption_key_file_generator.ignore_key_file(key_path)
83
85
  end
84
86
 
85
87
  def ensure_credentials_have_been_added
86
- if options[:environment]
87
- encrypted_file_generator.add_encrypted_file_silently(content_path, key_path)
88
- else
89
- credentials_generator.add_credentials_file_silently
90
- end
88
+ require "rails/generators/rails/credentials/credentials_generator"
89
+
90
+ Rails::Generators::CredentialsGenerator.new(
91
+ [content_path, key_path],
92
+ skip_secret_key_base: environment_specified? && %w[development test].include?(environment),
93
+ quiet: true
94
+ ).invoke_all
91
95
  end
92
96
 
93
97
  def change_credentials_in_system_editor
94
- credentials.change do |tmp_path|
95
- system(*Shellwords.split(ENV["EDITOR"]), tmp_path.to_s)
98
+ using_system_editor do
99
+ say "Editing #{content_path}..."
100
+ credentials.change { |tmp_path| system_editor(tmp_path) }
101
+ say "File encrypted and saved."
102
+ warn_if_credentials_are_invalid
96
103
  end
104
+ rescue ActiveSupport::EncryptedFile::MissingKeyError => error
105
+ say error.message
106
+ rescue ActiveSupport::MessageEncryptor::InvalidMessage
107
+ say "Couldn't decrypt #{content_path}. Perhaps you passed the wrong key?"
108
+ end
109
+
110
+ def warn_if_credentials_are_invalid
111
+ credentials.validate!
112
+ rescue ActiveSupport::EncryptedConfiguration::InvalidContentError => error
113
+ say "WARNING: #{error.message}", :red
114
+ say ""
115
+ say "Your application will not be able to load '#{content_path}' until the error has been fixed.", :red
97
116
  end
98
117
 
99
118
  def missing_credentials_message
100
- if credentials.key.nil?
101
- "Missing '#{key_path}' to decrypt credentials. See `bin/rails credentials:help`"
119
+ if !credentials.key?
120
+ "Missing '#{key_path}' to decrypt credentials. See `#{executable(:help)}`."
102
121
  else
103
- "File '#{content_path}' does not exist. Use `bin/rails credentials:edit` to change that."
122
+ "File '#{content_path}' does not exist. Use `#{executable(:edit)}` to change that."
104
123
  end
105
124
  end
106
125
 
107
- def content_path
108
- @content_path ||= options[:environment] ? "config/credentials/#{options[:environment]}.yml.enc" : "config/credentials.yml.enc"
109
- end
110
-
111
- def key_path
112
- options[:environment] ? "config/credentials/#{options[:environment]}.key" : "config/master.key"
126
+ def relative_path(path)
127
+ Rails.root.join(path).relative_path_from(Rails.root).to_s
113
128
  end
114
129
 
115
130
  def extract_environment_from_path(path)
116
- available_environments.find { |env| path.include? env } if path.end_with?(".yml.enc")
117
- end
118
-
119
- def encryption_key_file_generator
120
- require "rails/generators"
121
- require "rails/generators/rails/encryption_key_file/encryption_key_file_generator"
122
-
123
- Rails::Generators::EncryptionKeyFileGenerator.new
124
- end
125
-
126
- def encrypted_file_generator
127
- require "rails/generators"
128
- require "rails/generators/rails/encrypted_file/encrypted_file_generator"
129
-
130
- Rails::Generators::EncryptedFileGenerator.new
131
- end
132
-
133
- def credentials_generator
134
- require "rails/generators"
135
- require "rails/generators/rails/credentials/credentials_generator"
136
-
137
- Rails::Generators::CredentialsGenerator.new
131
+ available_environments.find { |env| path.end_with?("#{env}.yml.enc") }
138
132
  end
139
133
  end
140
134
  end
@@ -15,7 +15,8 @@ module Rails
15
15
  super
16
16
  end
17
17
 
18
- def perform
18
+ desc "change", "Change `config/database.yml` and your database gem to the target database"
19
+ def perform(*)
19
20
  Rails::Generators::Db::System::ChangeGenerator.start(@argv)
20
21
  end
21
22
  end