如何在 ActiveRecord 中从使用一个外键迁移到另一个外键?
How to migrate from using one foreign key to another in ActiveRecord?
使用 Postgres 作为后备存储,我有一个 table 它(至少目前)有一个整数主键和一个具有唯一索引的 uuid。
在我的 schema.rb
中看起来像这样(例如简化):
create_table "regions", force: cascade do |t|
t.integer "region_id"
t.uuid "uuid", default: "uuid_generate_v4()"
t.string "name"
end
add_index "regions", ["uuid"], name "index_regions_on_uuid", unique: true, using :btree
然后我有一个 table,它引用了整数 ID,如下所示:
create_table "sites", force:cascade do
t.integer "site_id"
t.integer "region_id"
t.string "name"
end
我想做的是把第二个table中的外键从region_id
切换到uuid
。我应该如何写这个迁移?
只需创建一个迁移,并向其中注入一些 SQL 魔法:
def up
# Create and fill in region_uuid column,
# joining records via still existing region_id column
add_column :sites, :region_uuid
if Site.reflect_on_association(:region).foreign_key == 'region_id'
# We won't use 'joins(:regions)' in case we will need
# to re-run migration later, when we already changed association
# code as suggested below. Specifying join manually instead.
Site.joins("INNER JOIN regions ON site.region_id = regions.id").update_all("region_uuid = regions.uuid")
end
drop_column :sites, :region_id
end
那么你只需要修复你的关联:
class Site < ActiveRecord::Base
belongs_to :region, primary_key: :uuid, foreign_key: :region_uuid
end
class Region < ActiveRecord::Base
has_many :sites, primary_key: :uuid, foreign_key: :region_uuid
end
从您的评论来看,您似乎想修改关联引用的主键,而不是外键。您实际上不需要迁移来执行此操作。相反,只需在每个模型的关联定义中指定主键:
Class Region << ActiveRecord::Base
has_many :sites, primary_key: :uuid
end
Class Site << ActiveRecord::Base
belongs_to :region, primary_key: :uuid
end
外键,因为它遵循 rails 命名为 belongs_to
关系并附加 "_id"
(在本例中为 region_id
)的约定,所以此处无需指定。
ETA: 您还需要确保 sites.region_id
的类型与 regions.uuid
的类型匹配,我假设是 uuid
.我还假设该字段之前已编入索引(根据 ActiveRecord 约定)并且您仍然希望它编入索引。您可以像这样在迁移中更改所有这些:
def up
remove_index :sites, :region_id
change_column :sites, :region_id, :uuid
add_index :sites, :region_id
end
def down
remove_index :sites, :region_id
change_column :sites, :region_id, :integer
add_index :sites, :region_id
end
使用 Postgres 作为后备存储,我有一个 table 它(至少目前)有一个整数主键和一个具有唯一索引的 uuid。
在我的 schema.rb
中看起来像这样(例如简化):
create_table "regions", force: cascade do |t|
t.integer "region_id"
t.uuid "uuid", default: "uuid_generate_v4()"
t.string "name"
end
add_index "regions", ["uuid"], name "index_regions_on_uuid", unique: true, using :btree
然后我有一个 table,它引用了整数 ID,如下所示:
create_table "sites", force:cascade do
t.integer "site_id"
t.integer "region_id"
t.string "name"
end
我想做的是把第二个table中的外键从region_id
切换到uuid
。我应该如何写这个迁移?
只需创建一个迁移,并向其中注入一些 SQL 魔法:
def up
# Create and fill in region_uuid column,
# joining records via still existing region_id column
add_column :sites, :region_uuid
if Site.reflect_on_association(:region).foreign_key == 'region_id'
# We won't use 'joins(:regions)' in case we will need
# to re-run migration later, when we already changed association
# code as suggested below. Specifying join manually instead.
Site.joins("INNER JOIN regions ON site.region_id = regions.id").update_all("region_uuid = regions.uuid")
end
drop_column :sites, :region_id
end
那么你只需要修复你的关联:
class Site < ActiveRecord::Base
belongs_to :region, primary_key: :uuid, foreign_key: :region_uuid
end
class Region < ActiveRecord::Base
has_many :sites, primary_key: :uuid, foreign_key: :region_uuid
end
从您的评论来看,您似乎想修改关联引用的主键,而不是外键。您实际上不需要迁移来执行此操作。相反,只需在每个模型的关联定义中指定主键:
Class Region << ActiveRecord::Base
has_many :sites, primary_key: :uuid
end
Class Site << ActiveRecord::Base
belongs_to :region, primary_key: :uuid
end
外键,因为它遵循 rails 命名为 belongs_to
关系并附加 "_id"
(在本例中为 region_id
)的约定,所以此处无需指定。
ETA: 您还需要确保 sites.region_id
的类型与 regions.uuid
的类型匹配,我假设是 uuid
.我还假设该字段之前已编入索引(根据 ActiveRecord 约定)并且您仍然希望它编入索引。您可以像这样在迁移中更改所有这些:
def up
remove_index :sites, :region_id
change_column :sites, :region_id, :uuid
add_index :sites, :region_id
end
def down
remove_index :sites, :region_id
change_column :sites, :region_id, :integer
add_index :sites, :region_id
end