使用 db:migrate:redo 正确处理架构更改引起的异常
我的迁移在几次架构更改期间中断。当它中断时,会引发异常并 rake db:migrate 退出,使我的数据库处于半迁移状态。
如何设置才能使迁移自动恢复到目前为止已运行的更改?我想在开发模式下在全球范围内这样做。当然,有人有比在 begin 中嵌入每个连续的
块。AR::Migration::ClassMethod
更好的方法;救援=>e 相反行动;结束
也许有一个常见的例子:
#2010010100000000_made_a_typo.rb
class MadeATypo < ActiveRecord::Migration
def self.up
rename_column :birds, :url, :photo_file_name
rename_column :birds, :genius, :species #typo on :genius => :genus
end
def self.down
rename_column :birds, :photo_file_name, :url
rename_column :birds, :species, :genius
end
end
此迁移将在第二行失败,并显示“未找到列天才”,但不会在 schema_migrations 表中记录迁移编号。 调用
rename_column :birds, :photo_file_name, :url #this is a revert of the first line
如果在异常从 MadeATypo.up
传递出去之前 。
对评论的回应:
我知道 mysql 可能不支持 DDL 事务,我正在寻找一个更多应用程序级别的解决方案,它(可能)使用 AR::Migration 本身。当然有人已经创建了一个插件,它可以捕获对主要 AR:M:ClassMethods 的方法调用,并且在大多数情况下如果迁移期间发生异常,可以回滚它们。
I have a migration that's breaking in the middle of a couple of schema changes. When it breaks an exception is thrown and rake db:migrate exits, leaving my database in a half-migrated state.
How can I set it up so that the migration automatically reverts just the changes that have run so far? I'd like to do so globally when in development mode. Surely someone out there has a better way than embedding each successive AR::Migration::ClassMethod
in a begin; rescue =>e opposite_action; end
block.
Perhaps a common example is in order:
#2010010100000000_made_a_typo.rb
class MadeATypo < ActiveRecord::Migration
def self.up
rename_column :birds, :url, :photo_file_name
rename_column :birds, :genius, :species #typo on :genius => :genus
end
def self.down
rename_column :birds, :photo_file_name, :url
rename_column :birds, :species, :genius
end
end
This migration will fail on the second line with "column genius not found", but not record the migration number in the schema_migrations table. I'd like it if it called
rename_column :birds, :photo_file_name, :url #this is a revert of the first line
before the exception was passed out of MadeATypo.up
.
Responses to comments:
I understand that mysql might not have support for DDL transactions, I'm looking for a more application-level solution which (probably) uses AR::Migration itself. Surely someone has created a plugin which captures method calls to the main AR:M:ClassMethods and can rewind them in most cases if an exception occurs during a migration.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我没有解决方案,但主要问题是DDL语句无法进行事务处理(至少在MySQL中,我不知道这是否是普遍现象)。
因此,由于迁移被视为原子向上/向下操作,因此没有简单的方法可以撤消“一半”迁移 - 找出
down
的哪些部分对应于down
的哪些部分并不容易。代码>向上I don't have a solution, but the main problem is that DDL statements can't be transactioned (at least in MySQL, I don't know if that's a general thing).
So, because migrations are treated as atomic up/down actions, there's no easy way to undo "half" a migration - it's not easy to work out which parts of the
down
correspond to which parts of theup
目前我不知道有什么方法可以做到这一点,但是 Rails 3.1 中的可逆迁移代码看起来是构建此功能的良好基础。请参阅以下链接:
我认为您可以实现此目的的方法是针对记录器运行迁移(如 https://github.com/rails/rails/commit/47017bd1697d6b4d6780356a403f91536eacd689#L0R337),然后切换回实时连接并一次运行记录器向前一个命令,跟踪有多少个命令已完成。那么,您所需要的就是将正向运行循环包装在 begin-rescue-end 中,如果出现异常,该循环将执行与成功执行正向命令一样多的反向命令。
I don't know of any way to do this currently, but the code for reversible migrations coming to Rails 3.1 looks like a good base to build this feature on. See these links:
The way I'm thinking you could implement this is to run the migration against the recorder (as in https://github.com/rails/rails/commit/47017bd1697d6b4d6780356a403f91536eacd689#L0R337), then switch back to the live connection and run the recorder forward one command at a time, tracking how many have completed. All you need, then, is to wrap that forward running loop in a begin-rescue-end that executes as many inverse commands as you successfully executed forward commands, if there's an exception.