将单表继承(STI)添加到现有模型

时间:2015-09-07 20:18:32

标签: ruby postgresql ruby-on-rails-4

我目前有多个非常相似的表。我应该用STI创建它们。

TypeOne < ActiveRecord::Base
TypeTwo < ActiveRecord::Base
TypeThree < ActiveRecord::Base

TypeOne(id: integer, parent_id: integer, created_at: datetime, updated_at: datetime)
TypeTwo(id: integer, parent_id: integer, created_at: datetime, updated_at: datetime)
TypeThree(id: integer, parent_id: integer, created_at: datetime, updated_at: datetime)

我现在正在尝试将STI添加到这些中。我创建了一个BaseModel并为该模型添加了一个类型。

BaseModel(id: integer, parent_id: integer, created_at: datetime, updated_at: datetime, type: string)

我还运行了迁移并添加到所有类型的类型列中。

class AddTypeToTables < ActiveRecord::Migration
  def change
    add_column :type_ones, :type, :string
    add_column :type_twos, :type, :string
    add_column :type_threes, :type, :string
  end
end

我想将所有类型表组合成一个STI。模型中存在现有数据。如果我将它们组合成一个表,我想相应表的id会发生冲突。例如:

#<TypeOne id: 4, parent_id: 1, created_at: "2015-05-08 18:39:09", updated_at: "2015-09-07 19:42:03">

#<TypeTwo id: 4, parent_id: 1, created_at: "2015-04-08 17:48:59", updated_at: "2015-09-07 14:17:48">

如果我尝试使用变成,它似乎改变了类,但我找不到BaseModel中的记录

TypeOne.last.becomes!(BaseModel)
#<BaseModel id: 4, parent_id: 1, created_at: "2015-05-08 18:39:09", updated_at: "2015-09-07 19:42:03">

BaseModel.all
=> []

我还尝试将继承表的type列更改为basemodel

to = TypeOne.first
to.type = "BaseModel"
to.save

BaseModel.all
=> []

我试图将每个类更改为BaseModel的子类

TypeOne < BaseModel
TypeTwo < BaseModel
TypeThree < BaseModel

当我这样做时,我失去了与现有数据的连接,并且每个模型都显示为空。

如何组合现有表?

1 个答案:

答案 0 :(得分:1)

正如您使用PostgreSQL标记的那样,我将在评论中包含如何做我建议的答案:

INSERT INTO base_model SELECT * FROM type_one ORDER BY id ASC;
INSERT INTO base_model SELECT * FROM type_two ORDER BY id ASC;
INSERT INTO base_model SELECT * FROM type_three ORDER BY id ASC;

要在生产数据集上安全地执行此操作,请将SQL放入db / migrate中的迁移中(即在db / migrate / 20150907185938_integrate_tables.rb之类的文件中),并首先在本地数据库上对其进行测试。这应该让你非常接近:

class IntegrateTables < ActiveRecord::Migration
  def up
    execute "INSERT INTO base_model SELECT * FROM type_one ORDER BY id ASC;"
    execute "INSERT INTO base_model SELECT * FROM type_two ORDER BY id ASC;"
    execute "INSERT INTO base_model SELECT * FROM type_three ORDER BY id ASC;"
  end

  def down
    raise ActiveRecord::IrreversibleMigration, "It is unclear where original data stops and inserted data begins, can't migrate down"
  end
end

请将此答案标记为已接受,如果它适用于您:)