Mat*_*man 8 ruby-on-rails ruby-on-rails-4
将大型遗留代码库从 UUID 转换为 ID。这需要分阶段完成,以保持许多设备之间的向后兼容性。
当前的解决方案是维护 UUID 和 ID 字段,直到我们可以完全过渡。
这样做的最佳方法是什么,以便所有belongs_to模型在每次创建/更新时都更新 ID 和 UUID?
示例:评论模型属于BlogPost,需要在创建/更新时同时设置blogpost_id& blogpost_uuid。
只需通过数据库即可:
假设您有这样的遗留表
class CreateLegacy < ActiveRecord::Migration
def change
enable_extension 'uuid-ossp'
create_table :legacies, id: :uuid do |t|
t.timestamps
end
create_table :another_legacies, id: false do |t|
t.uuid :uuid, default: 'uuid_generate_v4()', primary_key: true
t.timestamps
end
end
end
class Legacy < ActiveRecord::Base
end
class AnotherLegacy < ActiveRecord::Base
self.primary_key = 'uuid'
end
Run Code Online (Sandbox Code Playgroud)
有了上面的代码,你有:
Legacy.create.id # => "fb360410-0403-4388-9eac-c35f676f8368"
AnotherLegacy.create.id # => "dd45b2db-13c2-4ff1-bcad-3718cd119440"
Run Code Online (Sandbox Code Playgroud)
现在添加新的 id 列
class AddIds < ActiveRecord::Migration
def up
add_column :legacies, :new_id, :bigint
add_index :legacies, :new_id, unique: true
add_column :another_legacies, :id, :bigint
add_index :another_legacies, :id, unique: true
execute <<-SQL
CREATE SEQUENCE legacies_new_id_seq;
ALTER SEQUENCE legacies_new_id_seq OWNED BY legacies.new_id;
ALTER TABLE legacies ALTER new_id SET DEFAULT nextval('legacies_new_id_seq');
CREATE SEQUENCE another_legacies_id_seq;
ALTER SEQUENCE another_legacies_id_seq OWNED BY another_legacies.id;
ALTER TABLE another_legacies ALTER id SET DEFAULT nextval('another_legacies_id_seq');
SQL
end
def down
remove_column :legacies, :new_id
remove_column :another_legacies, :id
end
end
Run Code Online (Sandbox Code Playgroud)
创建新列后会添加默认值,因为这会阻止数据库尝试更新所有记录。=> 默认值将是新记录的默认值。
您可以根据需要回填旧的。
例如一一
Legacy.where(new_id: nil).find_each { |l| l.update_column(:new_id, ActiveRecord::Base.connection.execute("SELECT nextval('legacies_new_id_seq')")[0]['nextval'].to_i) }
AnotherLegacy.where(id: nil).find_each { |l| l.update_column(:id, ActiveRecord::Base.connection.execute("SELECT nextval('another_legacies_id_seq')")[0]['nextval'].to_i) }
Run Code Online (Sandbox Code Playgroud)
如果需要,您可以先回填,然后添加默认值,然后再次回填。
当您对这些值感到满意时,只需更改主键即可:
class Legacy < ActiveRecord::Base
self.primary_key = 'new_id'
def uuid
attributes['id']
end
end
class AnotherLegacy < ActiveRecord::Base
self.primary_key = 'id' # needed as we have not switched the PK in the db
end
Run Code Online (Sandbox Code Playgroud)
Legacy.first.id # => 1
Legacy.first.uuid # => "fb360410-0403-4388-9eac-c35f676f8368"
AnotherLegacy.first.id # => 1
AnotherLegacy.first.uuid # => "dd45b2db-13c2-4ff1-bcad-3718cd119440"
Run Code Online (Sandbox Code Playgroud)
最后,您需要再进行一次迁移以将主键更改为新 ID。
最重要的是避免停机:
附:不确定为什么要完全从 uuid 切换,如果要从外部应用程序引用记录,它们会更好
ps.2.0。如果您需要能够做到Legacy.find("fb360410-0403-4388-9eac-c35f676f8368"),Legacy.find(123)也许可以尝试https://github.com/norman/friendly_id
friendly_id :uuid, use: [:slugged, :finders]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1220 次 |
| 最近记录: |