何时可以在迁移的self.down方法中引发ActiveRecord :: IrreversibleMigration异常?您何时应该努力实际实现迁移的逆转?
答案 0 :(得分:53)
如果您正在处理生产级系统那么是的,这是非常糟糕的。如果这是你自己的宠物项目,那么任何事情都是允许的(如果没有别的话,这将是一次学习经历:)尽管很快就会有机会,即使在宠物项目中,你会发现自己已经跨越了反向迁移只需几天后撤消该迁移,无论是通过rake
还是手动。)
在生产场景中,您应该始终努力编写并测试可逆迁移,以防您在生产中经历它,然后发现错误这会迫使您回滚(代码和架构)到某些先前的修订版(等待一些非常重要的修复 - 以及一个原本无法使用的生产系统。)
反向迁移的范围大部分是微不足道的(删除在迁移期间添加的列或表,和/或更改列类型等),使其更加复杂(execute
JOIN
ed {{1 s}或INSERT
s),但没有什么比证明“将它扫到地毯下”更为复杂。如果不出意外,强迫自己想办法实现反向迁移可以让您对正向迁移正在修复的问题有新的认识。
您可能偶尔遇到正向迁移删除功能的情况,导致数据从数据库中丢弃。 出于显而易见的原因,反向迁移无法使丢弃的数据复苏。虽然在这种情况下,可以建议让正向迁移自动保存数据或在回滚的情况下保留数据作为直接替代失败(保存到UPDATE
,复制/移动到特殊表等),您不必,因为测试此类自动过程所需的时间可能超过手动恢复数据所需的时间(如果需要的话。)但即使在这种情况下,而不仅仅是失败,你总是可以有条不紊地暂时反向迁移等待某些用户操作(即测试必须手动恢复的某些必需表的存在;如果缺少,则输出“我失败了,因为我无法从虚无中重新创建表yml
;从备份手动恢复表XYZ
然后再次运行我,我不会让你失望!“)
答案 1 :(得分:28)
如果您要销毁数据,可以先备份数据。 e.g。
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
答案 2 :(得分:7)
在生产场景中,您应该始终努力编写和测试可逆迁移,以便在生产过程中进行可逆迁移,然后发现一个错误,迫使您回滚(代码和架构)到之前的某些版本修订版(等待一些非常重要的修复 - 以及其他无法使用的生产系统。)
进行可逆迁移对于开发和暂存来说是好的,但是假设经过良好测试的代码,您可能非常罕见地希望在生产中向下迁移。我在迁移中构建了一个生产模式下的自动IrreversibleMigration。如果我真的需要撤消更改,我可以使用另一个“向上”迁移或删除异常。这看起来很粗略。任何可能导致情况严重的错误都表明QA过程被严重搞砸了。
答案 3 :(得分:3)
感觉就像你需要一次不可逆转的迁移,这可能是一个迹象表明你已经遇到了更大的问题。也许某些细节会有所帮助吗?
关于你的第二个问题:我总是把'努力'写成反向迁移。当然, I 实际上并不写.down
,TextMate会在创建.up
时自动插入它。
答案 4 :(得分:3)
Reversible Data Migration可以使用yaml文件轻松创建可逆数据迁移。
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
答案 5 :(得分:2)
IIRC,在迁移中更改数据类型时,您将拥有IrreversibleMigration。
答案 6 :(得分:0)
我认为另一种情况是,当您进行整合迁移时。在这种情况下,“向下”并没有真正意义,因为它会丢弃所有表(除了合并后添加的表)。这可能不是你想要的。