【问题标题】:Deal with a drop_table migration for nonexistent table on heroku处理 heroku 上不存在的表的 drop_table 迁移
【发布时间】:2015-01-14 18:49:36
【问题描述】:

我在本地环境中的 postgres 数据库中创建了一个“活动”表。我从未提交更改,因此从未将其推送到 heroku 上的生产环境。

当我改变主意需要该表时,我愚蠢地手动删除了迁移(我现在知道永远不要这样做)。但是,由于迁移已经运行,我创建了一个 21041211003219_drop_campaigns_table 迁移以从本地数据库中删除表。

现在,当我在生产环境中运行 heroku run rake db:migrate 时,出现以下错误:

Migrating to DropCampaignsTable (20141211003219)                                                                                                                                                                                                     
== 20141211003219 DropCampaignsTable: migrating ===============================                                                                                                                                                                      
-- drop_table(:campaigns)                                                                                                                                                                                                                            
PG::UndefinedTable: ERROR:  table "campaigns" does not exist                                                                                                                                                                                         
: DROP TABLE "campaigns"                                                                                                                                                                                                                             
rake aborted!                                                                                                                                                                                                                                        
StandardError: An error has occurred, this and all later migrations canceled:                                                                                                                                                                        

PG::UndefinedTable: ERROR:  table "campaigns" does not exist                                                                                                                                                                                         
: DROP TABLE "campaigns"/app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:128:in `async_exec'                                                                            
/app/vendor/bundle/ruby/2.0.0/gems/activerecord-4.1.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:128:in `block in execute'             

我知道它正在尝试为一个它从未知道存在的表运行删除表迁移,但我不确定如何处理。

我尝试删除删除表迁移,推送到生产环境并运行它,但它仍然尝试运行该迁移。

回滚该提交后,我一直在考虑在重新创建表的 21041211003219_drop_campaigns_table 迁移之前手动创建一个带有日期戳的新迁移,但是我觉得我会留下现有的表本地 postgres 数据库(因为 21041211003219_drop_campaigns_table 已经在本地运行)。

我是否继续手动创建,然后尝试重新运行删除迁移?

有人可以告诉我这里的最佳行动方案吗?

【问题讨论】:

  • 您可以从 git 重新创建迁移。为了能够摆脱该错误,您可以使用heroku pg:psql 创建一个名为活动的表。在此控制台启动后,只需执行“创建表格活动......”。在执行此操作之前,您应该进行备份。
  • 为什么不直接删除该迁移?迁移并不是代码的永久组成部分,您应该不时清除它们。
  • @Octopus-Paul - +1 我没想到,下次会记住的
  • @muistooshort - 虽然我确实先尝试了这个(问题中的参考),但我确实再次尝试了这个(第一次没有正确推动)并且它确实有效。我认为您不应该删除迁移,以便将来从事该项目的其他任何人都可以运行它们并拥有准确的数据库。我假设您的意思是“清除它们”参考无用的参考,例如给我带来问题的那个。如果你想移动回答,我会接受。

标签: ruby-on-rails postgresql activerecord rails-activerecord


【解决方案1】:

您可以在删除已经不存在的表时关闭错误PG::UndefinedTable: ERROR: table "campaigns" does not exist,方法是将if_exists: true添加到drop_table

def up
  drop_table(:campaigns, if_exists: true)
end

此选项的文档很少,但存在于 Rails since early 2015 中,我认为它比手动编写 SQL 更干净,因为它还可以处理与各种 DB 适配器的兼容性。

【讨论】:

  • 很好的发现,我从来不知道if_exists
  • 对我不起作用,但这确实有效:table_exists?(:campaigns) ? drop_table(:campaigns) : nil
  • @MartinSommer - 你应该把这个作为答案。
【解决方案2】:

只需删除有问题的迁移,然后继续做更​​多有趣的事情。显然,该表没有“创建表”迁移,因此“删除表”迁移无权存在。如果您真的不想删除迁移,可以使用原始 SQL 重写它:

def up
  connection.execute 'drop table if exists campaigns'
end

if exists 完全符合您的想法:它只会尝试删除存在的表。

关于这些东西:

我认为您不应该删除迁移,以便将来从事该项目的其他任何人都可以运行它们并拥有准确的数据库。

迁移旨在将应用程序的现有实例从状态 A 转移到状态 B。如果您正在启动一个新实例,您将使用schema.rb(或structure.sql)来初始化应用程序,并且不需要迁移。此外,一旦将迁移应用到应用程序的每个实例,就不再需要迁移,除非您想尝试倒退。我倾向于在发布几周后清除旧的迁移以保持混乱。

【讨论】:

    【解决方案3】:

    if_exists 不适用于 Rails 4.2 和 PG 9.6。感谢@MartinSommer 提到table_exists?。对于后代,这是我使用的语法,读起来更干净。

    drop_table :campaigns if table_exists?(:campaigns)

    【讨论】:

      【解决方案4】:

      当您删除迁移文件并且想要删除相应的表时,例如student_items,有两种方法:

      1. 简单的方法:恢复迁移文件存档并运行

        rails db:rollback
        
      2. 创建迁移:

        rails g migration DropStudentItemTable
        

        并在迁移文件中添加此代码:

        class DropStudentItemTables < ActiveRecord::Migration[6.0]
          def down
            table_exists?(:student_items) ? drop_table(:student_items) : nil
          end
        end
        

      【讨论】:

      • 谢谢,我的英语很差,我会提高我的语言能力
      【解决方案5】:

      普通 SQL

        def down
          execute <<~SQL
            DROP TABLE IF EXISTS campaigns;
          SQL
        end
      

      【讨论】:

        猜你喜欢
        • 2016-09-04
        • 2015-11-01
        • 2019-11-15
        • 2014-08-08
        • 2021-06-17
        • 2021-07-13
        • 2018-10-23
        • 2018-02-12
        • 2015-10-25
        相关资源
        最近更新 更多