【问题标题】:How do i roll back this rails migration?如何回滚此 Rails 迁移?
【发布时间】:2019-12-06 03:35:46
【问题描述】:

我运行了以下迁移并忘记包含我想要的默认值。我正在尝试回滚它,以便我可以添加默认值并再次前滚。

20190728151635_add_cooldown_to_skill_levels.rb

class AddCooldownToSkillLevels < ActiveRecord::Migration[5.1]
  def change
    add_column :skill_levels, :cooldown, :integer
  end
end

所有 rails db:migrate 和 db:rollbacks 都失败并出现以下错误

$ rails db:rollback

== 20190728151635 AddCooldownToSkillLevels: reverting =========================
-- remove_column(:skill_levels, :cooldown, :integer)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::ConstraintException: FOREIGN KEY constraint failed: DROP TABLE "skill_levels"



And 100+ more lines ...

我尝试将迁移更改为使用明确的向上/向下方法无济于事

class AddCooldownToSkillLevels < ActiveRecord::Migration[5.1]
  def up
    add_column :skill_levels, :cooldown, :integer
  end

  def down
    remove_column :skill_levels, :cooldown
  end
end

我尝试添加一个只添加默认值的新迁移。

20190728153208_add_default_value_to_cooldown_on_skill_levels.rb

class AddDefaultValueToCooldownOnSkillLevels < ActiveRecord::Migration[5.1]
  def change
    change_column_default :skill_levels, :cooldown, 1
  end
end

类似的错误 $ rails db:迁移

== 20190728153208 AddDefaultValueToCooldownOnSkillLevels: migrating ===========
-- change_column_default(:skill_levels, :cooldown, 1)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::ConstraintException: FOREIGN KEY constraint failed: DROP TABLE "skill_levels"

And 100+ more lines ...

我很乐意直接在 SQL 中修复它,但我正在努力保持我的迁移完好无损。

编辑:添加 $ rails db:migrate:status 的输出

...
   up     20190727160901  Create skill levels
   up     20190728004535  Create skill effects
   up     20190728151635  Add cooldown to skill levels
  down    20190728153208  Add default value to cooldown on skill levels

感谢您的帮助。

【问题讨论】:

  • 帮自己一个忙,使用真正的数据库进行开发,postgres 是我的选择,但 mysql 也不错。
  • 这个问题似乎与 sqlite 如何处理 ALTER TABLE 命令有关。我没有证明这一点,但我相信可以在这里找到解决方案:sqlite.org 在“进行其他类型的表架构更改”部分。这个过程看起来很痛苦。
  • 已经在安装 pg.在这个烂摊子上每天损失 1/2。感谢上帝的单元测试。
  • 对你有好处,我希望 Rails 团队停止使用 sqlite 作为默认数据库,在 SO 上有一个又一个问题关于这个问题。

标签: ruby-on-rails sqlite ruby-on-rails-5 rails-migrations


【解决方案1】:

错误:

FOREIGN KEY constraint failed: DROP TABLE "skill_levels" 

告诉您有一个外键约束引用了您的 skill_levels 表(即在其他一些迁移中为 t.references :skill_levels, foreign_key: true),而 remove_column :skill_levels, :cooldown 导致了这个问题。

但是为什么在 ALTER TABLE 删除列期间数据库约束会成为问题?好吧,SQLite 的 ALTER TABLE doesn't support removing a column,而不是你必须(参见 SQLite 常见问题解答或 How to delete or add column in SQLITE?):

  1. 创建一个没有您要删除的列的新表。
  2. 将数据复制到新表中。
  3. 放弃原件。
  4. 重命名副本。

ActiveRecord 在幕后为您完成这项工作。步骤 (3) 是出了问题的地方,因为您无法删除外键约束引用的表。我认为您将手动处理外键:首先使用单独的updown 方法,然后将down 方法修改为:

  1. 删除所有引用您的表的外键,一旦您知道要处理哪些 FK,就可以使用 remove_foreign_key
  2. 然后remove_column :skill_levels, :cooldown 就像现在一样。
  3. 最后将所有 FK 放回原处,您可以为此使用 add_foreign_key

类似:

def down
  remove_foreign_key :some_table, :skill_levels
  remove_column :skill_levels, :cooldown
  add_foreign_key :some_table, :skill_levels
end

理想情况下,ActiveRecord 会为您解决这个问题,但大概 AR 的 SQLite 支持主要来自 AR 支持外键约束之前。

【讨论】:

  • 不走运。我什至在删除 FK 后添加了一个提交,然后为(本质上是表删除)列删除启动了一个新事务。 FK 全部成功删除,但随后失败并出现相同的错误。从一些额外的研究来看,这似乎有一个非常复杂的 12 步过程来解决,因为 sqllite 如何处理 ALTER TABLE。我认输,核对数据库并再次运行 $ rails db:setup 。这应该让我回到开发和测试的好位置,生产仍然落后于这次迁移,所以我应该没问题。感谢您的帮助。
猜你喜欢
  • 2018-10-31
  • 2015-12-07
  • 2011-10-31
  • 2010-10-15
  • 1970-01-01
  • 2014-06-21
  • 2011-03-15
  • 2017-09-03
  • 2011-06-24
相关资源
最近更新 更多