使用 db:migrate:redo 正确处理架构更改引起的异常

发布于 2024-09-25 15:41:31 字数 1019 浏览 1 评论 0原文

我的迁移在几次架构更改期间中断。当它中断时,会引发异常并 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

江南月 2024-10-02 15:41:31

我没有解决方案,但主要问题是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 the up

一个人的旅程 2024-10-02 15:41:31

目前我不知道有什么方法可以做到这一点,但是 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文