迁移数据 – 不仅仅是模式,Rails

有时,需要进行数据迁移。 随着时间的推移,使用域模型的代码更改和迁移不再有效,迁移失败。 迁移数据的最佳做法是什么?

我试过一个例子来澄清问题:

考虑一下。 你有一个迁移

class ChangeFromPartnerAppliedToAppliedAt < ActiveRecord::Migration def up User.all.each do |user| user.applied_at = user.partner_application_at user.save end end 

当然,这完全没问题。 稍后,您需要更改架构

 class AddAcceptanceConfirmedAt < ActiveRecord::Migration def change add_column :users, :acceptance_confirmed_at, :datetime end end class User < ActiveRecord::Base before_save :do_something_with_acceptance_confirmed_at end 

对你来说没问题。 它完美运行。 但是,如果您的同事今天同时进行了这两项操作, 但尚未运行第一次迁移那么在运行第一次迁移时会出现此错误:

 rake aborted! An error has occurred, this and all later migrations canceled: undefined method `acceptance_confirmed_at=' for # 

那不是团队合作者,他将修复你介绍的错误。 你应该怎么做?

最佳做法是:不要在迁移中使用模型。 迁移会改变AR映射的方式,因此根本不要使用它们。 用SQL做到这一切。 这样它总能工作。

这个:

 User.all.each do |user| user.applied_at = user.partner_application_at user.save end 

我会这样做的

 update "UPDATE users SET applied_at=partner_application_at" 

这是Using Models in Your Migrations的完美示例

 class ChangeFromPartnerAppliedToAppliedAt < ActiveRecord::Migration class User < ActiveRecord::Base end def up User.all.each do |user| user.applied_at = user.partner_application_at user.save end end 

米沙的评论后编辑

 class ChangeFromPartnerAppliedToAppliedAt < ActiveRecord::Migration class User < ActiveRecord::Base end def up User.update_all('applied_at = partner_application_at') end end 

有时候,“迁移数据”无法作为模式迁移的一部分执行,如上所述。 有时,“迁移数据”意味着“修复历史数据不一致”或“更新您的Solr / Elasticsearch”索引,因此这是一项复杂的任务。 对于这些任务,请查看此gem https://github.com/OffgridElectric/rails-data-migrations

此gem旨在将Rails架构迁移与数据迁移分离,因此它不会在部署时导致停机并使整体易于管理