diff --git a/actionmailbox/test/dummy/config/environments/development.rb b/actionmailbox/test/dummy/config/environments/development.rb index 38e89833f7..73e01778ff 100644 --- a/actionmailbox/test/dummy/config/environments/development.rb +++ b/actionmailbox/test/dummy/config/environments/development.rb @@ -46,10 +46,6 @@ Rails.application.configure do # Highlight code that triggered database queries in logs. config.active_record.verbose_query_logs = true - # Show a warning when Rails couldn't parse your database.yml - # for multiple databases. - config.active_record.suppress_multiple_database_warning = false - # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. diff --git a/actiontext/test/dummy/config/environments/development.rb b/actiontext/test/dummy/config/environments/development.rb index 38e89833f7..73e01778ff 100644 --- a/actiontext/test/dummy/config/environments/development.rb +++ b/actiontext/test/dummy/config/environments/development.rb @@ -46,10 +46,6 @@ Rails.application.configure do # Highlight code that triggered database queries in logs. config.active_record.verbose_query_logs = true - # Show a warning when Rails couldn't parse your database.yml - # for multiple databases. - config.active_record.suppress_multiple_database_warning = false - # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index dcb74cc87b..b2d85cc810 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,12 @@ +* Allow any ERB in the database.yml when creating rake tasks. + + Any ERB can be used in `database.yml` even if it accesses environment + configurations. + + Deprecates `config.active_record.suppress_multiple_database_warning`. + + *Eike Send* + * Add table to error for duplicate column definitions. If a migration defines duplicate columns for a table, the error message diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 1b6cc17c77..51959c83cf 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -336,12 +336,19 @@ module ActiveRecord singleton_class.attr_accessor :dump_schemas self.dump_schemas = :schema_search_path - ## - # :singleton-method: - # Show a warning when Rails couldn't parse your database.yml - # for multiple databases. - singleton_class.attr_accessor :suppress_multiple_database_warning - self.suppress_multiple_database_warning = false + def self.suppress_multiple_database_warning + ActiveSupport::Deprecation.warn(<<-MSG.squish) + config.active_record.suppress_multiple_database_warning is deprecated and will be removed in Rails 7.2. + It no longer has any effect and should be removed from the configuration file. + MSG + end + + def self.suppress_multiple_database_warning=(value) + ActiveSupport::Deprecation.warn(<<-MSG.squish) + config.active_record.suppress_multiple_database_warning= is deprecated and will be removed in Rails 7.2. + It no longer has any effect and should be removed from the configuration file. + MSG + end ## # :singleton-method: diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index e8485adbf4..9925eaf8b1 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -140,15 +140,7 @@ module ActiveRecord def setup_initial_database_yaml return {} unless defined?(Rails) - begin - Rails.application.config.load_database_yaml - rescue - unless ActiveRecord.suppress_multiple_database_warning - $stderr.puts "Rails couldn't infer whether you are using multiple databases from your database.yml and can't generate the tasks for the non-primary databases. If you'd like to use this feature, please simplify your ERB." - end - - {} - end + Rails.application.config.load_database_yaml end def for_each(databases) diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index df58c9c6f6..e96267cfd8 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -376,24 +376,34 @@ module Rails end end - # Load the database YAML without evaluating ERB. This allows us to - # create the rake tasks for multiple databases without filling in the - # configuration values or loading the environment. Do not use this - # method. + # Load the config/database.yml to create the Rake tasks for + # multiple databases without loading the environment and filling in the + # environment specific configuration values. # - # This uses a DummyERB custom compiler so YAML can ignore the ERB - # tags and load the database.yml for the rake tasks. + # Do not use this method, use #database_configuration instead. def load_database_yaml # :nodoc: if path = paths["config/database"].existent.first - require "rails/application/dummy_erb_compiler" + require "rails/application/dummy_config" - yaml = DummyERB.new(Pathname.new(path).read).result + original_rails_config = Rails.application.config + dummy_config = DummyConfig.new(original_rails_config) + database_config = {} - if YAML.respond_to?(:unsafe_load) - YAML.unsafe_load(yaml) || {} - else - YAML.load(yaml) || {} + begin + Rails.application.config = dummy_config + + yaml = ERB.new(Pathname.new(path).read).result + + if YAML.respond_to?(:unsafe_load) + database_config = YAML.unsafe_load(yaml) || {} + else + database_config = YAML.load(yaml) || {} + end + ensure + Rails.application.config = original_rails_config end + + database_config else {} end diff --git a/railties/lib/rails/application/dummy_config.rb b/railties/lib/rails/application/dummy_config.rb new file mode 100644 index 0000000000..c3edefc9a4 --- /dev/null +++ b/railties/lib/rails/application/dummy_config.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class DummyConfig # :nodoc: + def initialize(config) + @config = config + end + + def to_s + "DummyConfig" + end + + def method_missing(selector, *args, &blk) + if @config.respond_to?(selector) + @config.send(selector, *args, &blk) + else + self + end + end +end diff --git a/railties/lib/rails/application/dummy_erb_compiler.rb b/railties/lib/rails/application/dummy_erb_compiler.rb deleted file mode 100644 index 028e790292..0000000000 --- a/railties/lib/rails/application/dummy_erb_compiler.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -# These classes are used to strip out the ERB configuration -# values so we can evaluate the database.yml without evaluating -# the ERB values. -class DummyERB < ERB # :nodoc: - def make_compiler(trim_mode) - DummyCompiler.new trim_mode - end -end - -class DummyCompiler < ERB::Compiler # :nodoc: - def compile_content(stag, out) - if stag == "<%=" - out.push "_erbout << ''" - end - end -end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 6f3f796125..785a76560f 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -1741,9 +1741,16 @@ module ApplicationTests assert_not ActiveRecord.verbose_query_logs end - test "config.active_record.suppress_multiple_database_warning is false by default in development" do + test "config.active_record.suppress_multiple_database_warning getter is deprecated" do app "development" - assert_not ActiveRecord.suppress_multiple_database_warning + + assert_deprecated { ActiveRecord.suppress_multiple_database_warning } + end + + test "config.active_record.suppress_multiple_database_warning setter is deprecated" do + app "development" + + assert_deprecated { ActiveRecord.suppress_multiple_database_warning = true } end test "config.active_record.use_yaml_unsafe_load is false by default" do diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index d8b72e9203..b33bcd93d1 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -40,15 +40,6 @@ module ApplicationTests end end - def db_create_with_warning(expected_database) - Dir.chdir(app_path) do - output = rails("db:create") - assert_match(/Rails couldn't infer whether you are using multiple databases/, output) - assert_match(/Created database/, output) - assert File.exist?(expected_database) - end - end - test "db:create and db:drop without database URL" do require "#{app_path}/config/environment" db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, name: "primary") @@ -100,6 +91,25 @@ module ApplicationTests db_create_and_drop("db/development.sqlite3", environment_loaded: false) end + test "db:create and db:drop don't raise errors when loading YAML with alias ERB" do + app_file "config/database.yml", <<-YAML + sqlite: &sqlite + adapter: sqlite3 + database: db/development.sqlite3 + + development: + <<: *<%= ENV["DB"] || "sqlite" %> + YAML + + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.database = "db/development.sqlite3" + end + RUBY + + db_create_and_drop("db/development.sqlite3", environment_loaded: false) + end + test "db:create and db:drop don't raise errors when loading YAML with multiline ERB" do app_file "config/database.yml", <<-YAML development: @@ -118,23 +128,21 @@ module ApplicationTests db_create_and_drop("db/development.sqlite3", environment_loaded: false) end - test "db:create and db:drop show warning but doesn't raise errors when loading YAML with alias ERB" do + test "db:create and db:drop don't raise errors when loading ERB accessing nested configurations" do app_file "config/database.yml", <<-YAML - sqlite: &sqlite - adapter: sqlite3 - database: db/development.sqlite3 - development: - <<: *<%= ENV["DB"] || "sqlite" %> + database: db/development.sqlite3 + adapter: sqlite3 + other: <%= Rails.application.config.other.value %> YAML app_file "config/environments/development.rb", <<-RUBY Rails.application.configure do - config.database = "db/development.sqlite3" + config.other = OpenStruct.new(value: 123) end RUBY - db_create_with_warning("db/development.sqlite3") + db_create_and_drop("db/development.sqlite3", environment_loaded: false) end test "db:create and db:drop don't raise errors when loading YAML containing conditional statements in ERB" do diff --git a/railties/test/application/rake/multi_dbs_test.rb b/railties/test/application/rake/multi_dbs_test.rb index 1f8fbafd0a..6c06cab0e2 100644 --- a/railties/test/application/rake/multi_dbs_test.rb +++ b/railties/test/application/rake/multi_dbs_test.rb @@ -958,6 +958,19 @@ module ApplicationTests db_create_and_drop_namespace("primary", "db/development.sqlite3") end + test "db:create and db:drop don't raise errors when loading YAML containing ERB in database keys" do + app_file "config/database.yml", <<-YAML + development: + <% 5.times do |i| %> + shard_<%= i %>: + database: db/development_shard_<%= i %>.sqlite3 + adapter: sqlite3 + <% end %> + YAML + + db_create_and_drop_namespace("shard_3", "db/development_shard_3.sqlite3") + end + test "schema generation when dump_schema_after_migration is true schema_dump is false" do app_file "config/database.yml", <<~EOS development: