Skip to content

Commit 6e83d06

Browse files
authored
Merge pull request rails#43530 from eileencodes/support-setting-schema-path-in-config
Add support for setting the schema/structure dump filepath in the config
2 parents 6d7fdba + 059d64b commit 6e83d06

File tree

6 files changed

+124
-27
lines changed

6 files changed

+124
-27
lines changed

activerecord/CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
* Add support for setting the filename of the schema or structure dump in the database config.
2+
3+
Applications may now set their the filename or path of the schema / structure dump file in their database configuration.
4+
5+
6+
```yaml
7+
production:
8+
primary:
9+
database: my_db
10+
schema_dump: my_schema_dump_filename.rb
11+
animals:
12+
database: animals_db
13+
schema_dump: false
14+
```
15+
16+
The filename set in `schema_dump` will be used by the application. If set to `false` the schema will not be dumped. The database tasks are responsible for adding the database directory to the filename. If a full path is provided, the Rails tasks will use that instead of `ActiveRecord::DatabaseTasks.db_dir`.
17+
18+
*Eileen M. Uchitelle*, *Ryan Kerr*
19+
120
* Add `ActiveRecord::Base.prohibit_shard_swapping` to prevent attempts to change the shard within a block.
221

322
*John Crepezzi*, *Eileen M. Uchitelle*

activerecord/lib/active_record/database_configurations/hash_config.rb

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,39 @@ def primary? # :nodoc:
121121
Base.configurations.primary?(name)
122122
end
123123

124-
# Determines whether to dump the schema for a database.
125-
def schema_dump
126-
configuration_hash.fetch(:schema_dump, true)
124+
# Determines whether to dump the schema/structure files and the
125+
# filename that should be used.
126+
#
127+
# If +configuration_hash[:schema_dump]+ is set to +false+ or +nil+
128+
# the schema will not be dumped.
129+
#
130+
# If the config option is set that will be used. Otherwise Rails
131+
# will generate the filename from the database config name.
132+
def schema_dump(format = ActiveRecord.schema_format)
133+
if configuration_hash.key?(:schema_dump)
134+
if config = configuration_hash[:schema_dump]
135+
config
136+
end
137+
elsif primary?
138+
schema_file_type(format)
139+
else
140+
"#{name}_#{schema_file_type(format)}"
141+
end
127142
end
128143

129144
def database_tasks? # :nodoc:
130145
!replica? && !!configuration_hash.fetch(:database_tasks, true)
131146
end
147+
148+
private
149+
def schema_file_type(format)
150+
case format
151+
when :ruby
152+
"schema.rb"
153+
when :sql
154+
"structure.sql"
155+
end
156+
end
132157
end
133158
end
134159
end

activerecord/lib/active_record/tasks/database_tasks.rb

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,9 @@ def prepare_all
216216
dump_schema(db_config, ActiveRecord.schema_format)
217217
end
218218
rescue ActiveRecord::NoDatabaseError
219-
config_name = db_config.name
220-
create_current(db_config.env_name, config_name)
219+
create_current(db_config.env_name, db_config.name)
221220

222-
if File.exist?(dump_filename(config_name))
221+
if File.exist?(schema_dump_path(db_config))
223222
load_schema(
224223
db_config,
225224
ActiveRecord.schema_format,
@@ -378,7 +377,7 @@ def structure_load(configuration, *arguments)
378377
end
379378

380379
def load_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
381-
file ||= dump_filename(db_config.name, format)
380+
file ||= schema_dump_path(db_config, format)
382381

383382
verbose_was, Migration.verbose = Migration.verbose, verbose? && ENV["VERBOSE"]
384383
check_schema_file(file)
@@ -406,9 +405,7 @@ def schema_up_to_date?(configuration, format = ActiveRecord.schema_format, file
406405
ActiveSupport::Deprecation.warn("`environment` and `name` will be removed as parameters in 7.0.0, you may now pass an ActiveRecord::DatabaseConfigurations::DatabaseConfig as `configuration` instead.")
407406
end
408407

409-
name ||= db_config.name
410-
411-
file ||= dump_filename(name, format)
408+
file ||= schema_dump_path(db_config)
412409

413410
return true unless File.exist?(file)
414411

@@ -421,7 +418,7 @@ def schema_up_to_date?(configuration, format = ActiveRecord.schema_format, file
421418
end
422419

423420
def reconstruct_from_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
424-
file ||= dump_filename(db_config.name, format)
421+
file ||= schema_dump_path(db_config, format)
425422

426423
check_schema_file(file)
427424

@@ -440,7 +437,7 @@ def reconstruct_from_schema(db_config, format = ActiveRecord.schema_format, file
440437

441438
def dump_schema(db_config, format = ActiveRecord.schema_format) # :nodoc:
442439
require "active_record/schema_dumper"
443-
filename = dump_filename(db_config.name, format)
440+
filename = schema_dump_path(db_config, format)
444441
connection = ActiveRecord::Base.connection
445442

446443
FileUtils.mkdir_p(db_dir)
@@ -475,6 +472,8 @@ def schema_file_type(format = ActiveRecord.schema_format)
475472
end
476473

477474
def dump_filename(db_config_name, format = ActiveRecord.schema_format)
475+
ActiveSupport::Deprecation.warn("#dump_filename is deprecated. Please call `schema_dump_path` or call `schema_dump` on the `db_config` directly.")
476+
478477
filename = if ActiveRecord::Base.configurations.primary?(db_config_name)
479478
schema_file_type(format)
480479
else
@@ -484,6 +483,19 @@ def dump_filename(db_config_name, format = ActiveRecord.schema_format)
484483
ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
485484
end
486485

486+
def schema_dump_path(db_config, format = ActiveRecord.schema_format)
487+
return ENV["SCHEMA"] if ENV["SCHEMA"]
488+
489+
filename = db_config.schema_dump(format)
490+
return unless filename
491+
492+
if File.dirname(filename) == ActiveRecord::Tasks::DatabaseTasks.db_dir
493+
filename
494+
else
495+
File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
496+
end
497+
end
498+
487499
def cache_dump_filename(db_config_name, schema_cache_path: nil)
488500
filename = if ActiveRecord::Base.configurations.primary?(db_config_name)
489501
"schema_cache.yml"

activerecord/test/cases/database_configurations/hash_config_test.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,12 @@ def test_idle_timeout_nil_when_less_than_or_equal_to_zero
105105

106106
def test_default_schema_dump_value
107107
config = HashConfig.new("default_env", "primary", {})
108-
assert_equal true, config.schema_dump
108+
assert_equal "schema.rb", config.schema_dump
109109
end
110110

111-
def test_schema_dump_value_set_to_true
112-
config = HashConfig.new("default_env", "primary", { schema_dump: true })
113-
assert_equal true, config.schema_dump
111+
def test_schema_dump_value_set_to_filename
112+
config = HashConfig.new("default_env", "primary", { schema_dump: "my_schema.rb" })
113+
assert_equal "my_schema.rb", config.schema_dump
114114
end
115115

116116
def test_schema_dump_value_set_to_nil
@@ -120,7 +120,7 @@ def test_schema_dump_value_set_to_nil
120120

121121
def test_schema_dump_value_set_to_false
122122
config = HashConfig.new("default_env", "primary", { schema_dump: false })
123-
assert_equal false, config.schema_dump
123+
assert_nil config.schema_dump
124124
end
125125

126126
def test_database_tasks_defaults_to_true

activerecord/test/cases/tasks/database_tasks_test.rb

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,27 @@ class DatabaseTasksDumpSchemaTest < ActiveRecord::TestCase
298298
def test_ensure_db_dir
299299
Dir.mktmpdir do |dir|
300300
ActiveRecord::Tasks::DatabaseTasks.stub(:db_dir, dir) do
301-
db_config = OpenStruct.new(name: "fake_db_config")
301+
updated_hash = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary").configuration_hash.merge(schema_dump: "fake_db_config_schema.rb")
302+
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("arunit", "primary", updated_hash)
303+
path = "#{dir}/fake_db_config_schema.rb"
304+
305+
FileUtils.rm_rf(dir)
306+
assert_not File.file?(path)
307+
308+
ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config)
309+
310+
assert File.file?(path)
311+
end
312+
end
313+
ensure
314+
ActiveRecord::Base.clear_cache!
315+
end
316+
317+
def test_db_dir_ignored_if_included_in_schema_dump
318+
Dir.mktmpdir do |dir|
319+
ActiveRecord::Tasks::DatabaseTasks.stub(:db_dir, dir) do
320+
updated_hash = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary").configuration_hash.merge(schema_dump: "#{dir}/fake_db_config_schema.rb")
321+
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("arunit", "primary", updated_hash)
302322
path = "#{dir}/fake_db_config_schema.rb"
303323

304324
FileUtils.rm_rf(dir)
@@ -1598,7 +1618,17 @@ def test_check_schema_file_defaults
15981618
def test_check_dump_filename_defaults
15991619
ActiveRecord::Tasks::DatabaseTasks.stub(:db_dir, "/tmp") do
16001620
with_stubbed_configurations do
1601-
assert_equal "/tmp/schema.rb", ActiveRecord::Tasks::DatabaseTasks.dump_filename(config_for("development", "primary").name)
1621+
assert_equal "/tmp/schema.rb", ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(config_for("development", "primary"))
1622+
end
1623+
end
1624+
end
1625+
1626+
def test_dump_filename_is_deprecated
1627+
ActiveRecord::Tasks::DatabaseTasks.stub(:db_dir, "/tmp") do
1628+
with_stubbed_configurations do
1629+
assert_deprecated do
1630+
assert_equal "/tmp/schema.rb", ActiveRecord::Tasks::DatabaseTasks.dump_filename(config_for("development", "primary").name)
1631+
end
16021632
end
16031633
end
16041634
end
@@ -1608,7 +1638,7 @@ def test_check_dump_filename_with_schema_env
16081638
ENV["SCHEMA"] = "schema_path"
16091639
ActiveRecord::Tasks::DatabaseTasks.stub(:db_dir, "/tmp") do
16101640
with_stubbed_configurations do
1611-
assert_equal "schema_path", ActiveRecord::Tasks::DatabaseTasks.dump_filename(config_for("development", "primary").name)
1641+
assert_equal "schema_path", ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(config_for("development", "primary"))
16121642
end
16131643
end
16141644
ensure
@@ -1619,7 +1649,7 @@ def test_check_dump_filename_with_schema_env
16191649
define_method("test_check_dump_filename_for_#{fmt}_format") do
16201650
ActiveRecord::Tasks::DatabaseTasks.stub(:db_dir, "/tmp") do
16211651
with_stubbed_configurations do
1622-
assert_equal "/tmp/#{filename}", ActiveRecord::Tasks::DatabaseTasks.dump_filename(config_for("development", "primary").name, fmt)
1652+
assert_equal "/tmp/#{filename}", ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(config_for("development", "primary"), fmt)
16231653
end
16241654
end
16251655
end
@@ -1631,7 +1661,18 @@ def test_check_dump_filename_defaults_for_non_primary_databases
16311661
"development" => { "primary" => { "database" => "dev-db" }, "secondary" => { "database" => "secondary-dev-db" } },
16321662
}
16331663
with_stubbed_configurations(configurations) do
1634-
assert_equal "/tmp/secondary_schema.rb", ActiveRecord::Tasks::DatabaseTasks.dump_filename(config_for("development", "secondary").name)
1664+
assert_equal "/tmp/secondary_schema.rb", ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(config_for("development", "secondary"))
1665+
end
1666+
end
1667+
end
1668+
1669+
def test_setting_schema_dump_to_nil
1670+
ActiveRecord::Tasks::DatabaseTasks.stub(:db_dir, "/tmp") do
1671+
configurations = {
1672+
"development" => { "primary" => { "database" => "dev-db", "schema_dump" => false } },
1673+
}
1674+
with_stubbed_configurations(configurations) do
1675+
assert_nil ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(config_for("development", "primary"))
16351676
end
16361677
end
16371678
end
@@ -1644,7 +1685,7 @@ def test_check_dump_filename_with_schema_env_with_non_primary_databases
16441685
"development" => { "primary" => { "database" => "dev-db" }, "secondary" => { "database" => "secondary-dev-db" } },
16451686
}
16461687
with_stubbed_configurations(configurations) do
1647-
assert_equal "schema_path", ActiveRecord::Tasks::DatabaseTasks.dump_filename(config_for("development", "secondary").name)
1688+
assert_equal "schema_path", ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(config_for("development", "secondary"))
16481689
end
16491690
end
16501691
ensure
@@ -1658,7 +1699,7 @@ def test_check_dump_filename_with_schema_env_with_non_primary_databases
16581699
"development" => { "primary" => { "database" => "dev-db" }, "secondary" => { "database" => "secondary-dev-db" } },
16591700
}
16601701
with_stubbed_configurations(configurations) do
1661-
assert_equal "/tmp/secondary_#{filename}", ActiveRecord::Tasks::DatabaseTasks.dump_filename(config_for("development", "secondary").name, fmt)
1702+
assert_equal "/tmp/secondary_#{filename}", ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(config_for("development", "secondary"), fmt)
16621703
end
16631704
end
16641705
end

railties/test/application/rake/migrations_test.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,21 +425,21 @@ class TwoMigration < ActiveRecord::Migration::Current
425425
assert_match(/up\s+002\s+Two migration/, output)
426426
end
427427

428-
test "schema generation when dump_schema_after_migration and schema_dump are true" do
428+
test "schema generation when dump_schema_after_migration and schema_dump are set" do
429429
add_to_config("config.active_record.dump_schema_after_migration = true")
430430

431431
app_file "config/database.yml", <<~EOS
432432
development:
433433
adapter: sqlite3
434434
database: 'dev_db'
435-
schema_dump: true
435+
schema_dump: "schema_file.rb"
436436
EOS
437437

438438
Dir.chdir(app_path) do
439439
rails "generate", "model", "book", "title:string"
440440
rails "db:migrate"
441441

442-
assert File.exist?("db/schema.rb"), "should dump schema when configured to"
442+
assert File.exist?("db/schema_file.rb"), "should dump schema when configured to"
443443
end
444444
end
445445

0 commit comments

Comments
 (0)