添加多态关联后如何迁移现有数据?

How to migrate existing data after adding polymorphic association?

迁移后,我的 PageViewStats table 包含 2 个新的空列: ad_templatable_idad_templatable_type。因此,如果我尝试像这样查询现有记录:AdTemplate.find(42).page_view_stats 它 returns 什么都没有,但在迁移之前 returns 数组 PageViewStats 记录。

我想我需要创建一个 rake 任务来填充这两个新列:

1) ad_templatable_id 将包含来自现有 ad_template_id 列的值

2) ad_templatable_type 将包含一个字符串 AdTemplate

我猜对了吗? :) 这是我需要做的吗?

迁移前:

# == Schema Information
# #  ad_template_id      :integer          not null
class PageViewStat < ActiveRecord::Base
  belongs_to :ad_template
end

class AdTemplate < ActiveRecord::Base
  has_many :page_view_stats
end

应用多态迁移:

class AddPolymorphismToPageViewStat < ActiveRecord::Migration
  def change
    add_reference :page_view_stats, :ad_templatable, polymorphic: true
    add_index :page_view_stats, [:ad_templatable_type, :ad_templatable_id],
               name: 'index_page_view_stats_on_ad_templatable_type_and_id'
  end
end

迁移后:

# == Schema Information
# #  ad_template_id      :integer          not null
class PageViewStat < ActiveRecord::Base
  belongs_to :ad_templatable, polymorphic: true
end

class AdTemplate < ActiveRecord::Base
  has_many :page_view_stats, as: :ad_templatable
end

是的,创建 rake 任务比手动执行数据迁移更好,因为您可以为其编写测试。

另一种方法是在迁移中包含更改数据的代码,这非常有助于确保在架构更改时迁移数据,减少潜在的停机时间,例如

def up
  [code to add new columns]

  migrate_data

  [code to remove legacy columns]
end

def down
  [code to add legacy columns]

  rollback_data

  [code to remove new columns]
end

private

def migrate_data
  [code to make data changes]
end

def rollback_data
  [code to reverse data changes]
end

注意,如果你这样做,有一些陷阱,你将需要分别指定向上和向下迁移,并且你应该通过编写代码来回滚和测试。