使用Postgres作为后备存储,我有一个表(至少暂时)有一个整数主键和一个具有唯一索引的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
然后我有一个表,它引用了整数id,如下所示:
create_table "sites", force:cascade do
t.integer "site_id"
t.integer "region_id"
t.string "name"
end
我想要做的是从region_id
切换到uuid
作为第二个表中的外键。我应该如何写这个迁移呢?
答案 0 :(得分:2)
只需创建一个迁移,并吸入一些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
答案 1 :(得分:2)
从您的评论中,您似乎想要修改关联引用的主键,而不是外键。您实际上不需要迁移来执行此操作。相反,只需在每个模型中的关联定义上指定主键:
Class Region << ActiveRecord::Base
has_many :sites, primary_key: :uuid
end
Class Site << ActiveRecord::Base
belongs_to :region, primary_key: :uuid
end
外键,因为它跟随被称为belongs_to
关系的rails约定与附加的"_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