Rails:不可逆转的迁移是不是很糟糕?
什么时候在迁移的self.down方法中引发ActiveRecord :: IrreversibleMigrationexception是可以接受的? 什么时候应该采取措施实际执行迁移的逆向工作?
如果你正在处理生产级系统,那么是的,这是非常糟糕的。 如果这是你自己的宠物项目,那么任何事情都是允许的(如果没有其他的东西,这将是一个学习的经验:)虽然机会是早日而不是晚,即使在一个宠物项目,你会发现自己已经跨越反向迁移只能在几天后撤销迁移,通过rake
或手动迁移)。
在生产场景中,您应该始终努力编写和testing可逆迁移 ,以避免在生产过程中发生可逆迁移 ,然后发现一个迫使您回滚(代码和模式)到某个以前版本(等待一些不重要的修复 – 和一个不可用的生产系统。)
反向迁移的范围从大多数不重要(删除在迁移过程中添加的列或表,和/或更改列types等)到更多地涉及( execute
JOIN
INSERT
或UPDATE
),但没有任何复杂certificate“在地毯之下”。 如果没有别的办法,强迫自己想办法实现逆向迁移,可以让你对你的向前迁移正在解决的问题有新的认识。
您可能偶尔遇到正向迁移删除function的情况,导致数据从数据库中丢弃。 由于显而易见的原因,反向迁移不能复原丢弃的数据。 虽然在这种情况下,可以推荐使用向前迁移自动保存数据或将其保留在回滚事件中,以作为彻底失败的替代方法(保存到yml
,复制/移动到特殊表格等)因为testing这样一个自动化程序所需的时间可能会超过手动恢复数据所需的时间(如果需要的话)。 但是即使在这种情况下 ,您也可以始终做到相反迁移有条件地暂时失败,等待某些用户操作(即testing是否存在必须手动恢复的某些必需表;如果缺less,则输出“我失败了,因为我无法从虚拟表中重新创build表XYZ
;然后从备份中手动恢复表XYZ
再次运行我,我不会让你失望!“)
如果您正在销毁数据,则可以先对其进行备份。 例如
def self.up # create a backup table before destroying data execute %Q[create table backup_users select * from users] remove_column :users, :timezone end def self.down add_column :users, :timezone, :string execute %Q[update users U left join backup_users B on (B.id=U.id) set U.timezone = B.timezone] execute %Q[drop table backup_users] end
在生产场景中,您应该始终努力编写和testing可逆迁移,以避免在生产过程中发生可逆迁移,然后发现一个迫使您回滚(代码和模式)到某个以前版本(等待一些不重要的修复 – 和一个不可用的生产系统。)
进行可逆迁移对于开发和分期来说是很好的,但假设经过良好testing的代码,您将永远不想迁移到生产环境中。 我在生产模式中将自动IrreversibleMigrationjoin到迁移中。 如果我真的需要扭转变化,我可以使用另一个“向上”迁移或删除exception。 这似乎粗略,但。 任何可能导致这种可怕情况的错误都是QA过程被严重搞砸的标志。
感觉像你需要一个不可逆转的迁移可能是一个迹象,你有更大的问题迫在眉睫。 也许有些细节会有所帮助?
至于你的第二个问题:我总是把这个“努力”写成迁移的反面。 当然, 我实际上没有编写.down
,TextMate在创build.up
时会自动插入它。
可逆数据迁移使用yaml文件轻松创build可逆数据迁移 。
class RemoveStateFromProduct < ActiveRecord::Migration def self.up backup_data = [] Product.all.each do |product| backup_data << {:id => product.id, :state => product.state} end backup backup_data remove_column :products, :state end def self.down add_column :products, :state, :string restore Product end end
IIRC,在迁移中更改数据types时,您将拥有不可逆迁移。
我认为可以的另一种情况是当你有一个统一的迁移。 在这种情况下,“下”并不是真的有意义,因为它会删除所有表(除了在合并之后添加的表)。 这可能不是你想要的。