[Rails] PostgreSQLスキーマダンパーにおけるクロススキーマ外部キー参照の修正
問題の概要
RailsのPostgreSQLスキーマダンパーには、異なるスキーマ間の外部キー制約をダンプする際に、誤ってスキーマ名を重複して付与してしまうバグがありました。具体的には、参照先テーブルが既にスキーマ修飾されている場合(schema.table形式)でも、さらに別のスキーマ名を先頭に付与してしまう問題です。
例えば、hst.event_log_attributesからusr.user_profilesへの外部キーが、ダンプ時にhst.usr.user_profilesとして出力されてしまい、実際には存在しないテーブル名になっていました。
技術的な変更内容
修正箇所
relation_nameメソッドに、既にスキーマ修飾された名前かどうかをチェックするロジックが追加されました。
変更前:
def relation_name(name)
if @dump_schemas.size == 1
name
else
"#{schema_name}.#{name}"
end
end
変更後:
def relation_name(name)
if @dump_schemas.size == 1
name
elsif name.include?(".")
name # Already schema-qualified, don't add another prefix
else
"#{schema_name}.#{name}"
end
end
動作の違い
修正により、スキーマダンプの出力が以下のように変わります。
修正前:
add_foreign_key "hst.event_log_attributes", "hst.event_logs"
add_foreign_key "hst.event_log_attributes", "hst.usr.user_profiles", column: "created_by_id"
修正後:
add_foreign_key "hst.event_log_attributes", "hst.event_logs"
add_foreign_key "hst.event_log_attributes", "usr.user_profiles", column: "created_by_id"
テストケースの追加
異なるスキーマ間の外部キー制約を正しくダンプできることを確認するテストが追加されました。
def test_schema_dump_with_cross_schema_foreign_key
with_dump_schemas(:all) do
output = dump_all_table_schema
assert_includes output, 'add_foreign_key "test_schema.cross_schema_fk_table", "test_schema2.referenced_table"'
assert_not_includes output, 'add_foreign_key "test_schema.cross_schema_fk_table", "test_schema.test_schema2.referenced_table"'
end
end
このテストでは、test_schema.cross_schema_fk_tableからtest_schema2.referenced_tableへの外部キーが正しくダンプされること、そして誤った形式(スキーマ名の重複)では出力されないことを確認しています。
影響範囲
この修正は以下のような環境で効果を発揮します:
- PostgreSQLで複数のスキーマを使用している
- 異なるスキーマ間で外部キー制約を設定している
-
db:schema:dumpやdb:structure:dumpを実行してスキーマファイルを生成している
修正により、ダンプされたスキーマファイルを使用してデータベースを再構築する際に、正しいテーブル名で外部キー制約が作成されるようになります。