Rails数据库迁移 - 如何删除一个表?

580

我添加了一张表,但现在不再需要它了。该如何删除这个表?

我已经运行了迁移,所以这个表已经存在于我的数据库中。我认为rails generate migration应该可以处理这个问题,但我还没有找到具体方法。

我尝试过:

rails generate migration drop_tablename

但那只生成了一个空的迁移。

在Rails中删除表的“官方”方法是什么?


1
由于rails generate migration具有用于生成创建表、添加或更改列等迁移代码的命令行选项,因此如果它还有一个删除表的选项就好了——但它没有。当然,编写“up”部分很简单——只需调用drop_table即可——但是“down”部分,重新生成表可能并不总是那么简单,特别是如果该表的模式在初始创建后被迁移更改了。也许应该建议Rails的开发人员添加这样一个选项是个好主意。 - Teemu Leisti
5
@TeemuLeisti 你觉得直接从schema.rb中复制当前表的定义如何?我经常这样做... - jasoares
1
@João Soares:好的,我想那样应该可以。不过,如果能够自动化这个过程就更好了,这样你只需要给出一个rake迁移创建命令,并附带一个表名作为参数,就可以生成所需的updown函数。 - Teemu Leisti
1
我在GitHub上为此打开了一个PR:https://github.com/rails/rails/pull/48729目前还不能撤销(我和@TeemuLeisti有相同的担忧),但也许其他人可以改进。 - knagode
24个回答

708

有时候你不能简单地生成已经包含你想要的代码的迁移文件。你可以创建一个空的迁移文件,然后填充你需要的代码。

你可以在这里找到关于如何完成不同任务的迁移文件的信息:

http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

更具体地,你可以看到如何使用下面的方法删除一个表:

drop_table :table_name

3
这对我也起作用了。但在完整迁移(从头安装)时,该表现在将首先被创建,然后再被删除。以后删除创建和删除迁移是否安全? - berkes
3
在这里,你认为删除表格还是恢复到先前的数据库模式更好? - william tell
4
如果你不再需要使用这张表格,我会建议你将其删掉。如果它不再被使用,最好把它清除掉。 - Pete
9
@BederAcostaBorges的回答更加自我解释和准确。 - onerinas
3
如何删除所有外键?其他表中有列指向要被删除的表。 - Martin Konicek
显示剩余3条评论

389

手动编写迁移。例如运行rails g migration DropUsers

至于迁移的代码,我将引用Maxwell Holder的文章《Rails 迁移清单》

不好的做法 - 运行rake db:migrate 然后 rake db:rollback 将会失败

class DropUsers < ActiveRecord::Migration
  def change
    drop_table :users
  end
end

GOOD - 显示了迁移不应该是可逆的意图

class DropUsers < ActiveRecord::Migration
  def up
    drop_table :users
  end

  def down
    fail ActiveRecord::IrreversibleMigration
  end
end

BETTER - 可以实现反向操作

class DropUsers < ActiveRecord::Migration
  def change
    drop_table :users do |t|
      t.string :email, null: false
      t.timestamps null: false
    end
  end
end

9
如果你正在从schema.rb中进行剪切和粘贴,请不要忘记还要在schema.rb中搜索外键。然后将外键定义添加到drop_table块中,例如:t.foreign_key "other_table" - Lencho Reyes
2
我使用了第三个选项,对我来说完美地解决了问题。谢谢。 - Promise Preston
谢谢@Beder Acosta Borges。我一直在想如何正确地进行可逆迁移。在我的情况下,是要删除两个不需要的表。所以我基本上生成了迁移,并从原始迁移中复制了内容,将create_table更改为drop_table,但保留了do |t|块和所有列,它完美地工作了!TY! - Scott Milella

380

首先生成一个空的迁移,可以随意命名。这样做很重要,因为它会创建适当的日期。

rails generate migration DropProductsTable

这将会在/db/migrate/中生成一个.rb文件,例如20111015185025_drop_products_table.rb。

现在编辑该文件,使其看起来像这样:

class DropProductsTable < ActiveRecord::Migration
  def up
    drop_table :products
  end

  def down
    raise ActiveRecord::IrreversibleMigration
  end
end

我所做的唯一更改是添加了 drop_table :productsraise ActiveRecord::IrreversibleMigration

然后运行 rake db:migrate,它将帮助您删除该表。


17
应使用“下行迁移”来重新创建被删除的表格。 - fflyer05
2
这个迁移无法回滚,即使在开发中也不行。留空下降迁移是否更好? - mhriess
1
这是更好的答案 + fflyer的评论 - Zack Shapiro
2
@mjnissim和fflyer05是正确的,在避免任何奇怪的事情发生时,您应该在down方法中重新创建表。 - Sebastialonso
1
为了使迁移可逆,修改代码如下。我更喜欢使用change方法,而不是单独的up和down方法,这样相同的代码可以双向工作。def change; drop_table :products do |t|; t.string :product_name, null: false; t.timestamps null: false; end; end; - user3402754
14
删除一张表会删除其中所有数据,如果你在“down”方法中重新创建它,你将无法恢复其中的数据,因此这实际上不是一个正确的回滚操作。最好明确指出迁移是不可逆的,而不是给人一种错误的恢复感觉。 - vivi

217
警告: 请自行承担风险,正如@z-atef和@nzifnab正确指出的那样,Rails不会意识到这些更改,您的迁移序列将失败,并且您的模式将与同事的不同。这仅是用于本地开发调试的资源。


虽然这里提供的答案能够正常工作,但我想要一些更加“直接”的方法,我在这里找到了: link。首先进入rails控制台:

$rails console

然后只需要输入:

ActiveRecord::Migration.drop_table(:table_name)

完成了,对我有用!


该模型仍然存在,直到您运行 rails destroy model User 命令。 - gm2008
3
仅在您希望永久删除表格时运行此命令。Rails 将不知道此删除操作。运行此命令后,迁移将被破坏,无法进行 CREATE、DROP 等操作。错误信息为 SQLite3::SQLException: no such table: accruals,DROP TABLE "sometable"。 - z atef
警告:不要这样做。您绝不能直接从控制台执行DDL操作。您的结构文件将不知道已进行此更改,您的同事开发环境将与您自己和生产环境不同,这只会造成混乱。请使用迁移。 - nzifnab
确实,只有在表格仅存在于您的本地数据库中,没有人关心该表格中的数据,并且迁移已被删除且不易恢复时,才应该执行此操作。因此,它不会影响其他可以访问存储库的人。例如:我只有在生成模型、运行迁移然后销毁脚手架(因为有拼写错误或其他原因)而没有先撤销迁移时才这样做。(删除表格比尝试恢复已删除的迁移更快) - Nuclearman

38

您需要使用以下命令创建一个新的迁移文件

rails generate migration drop_table_xyz

在新生成的迁移文件(db/migration/xxxxxxx_drop_table_xyz)中编写删除表格的代码,例如:

and write drop_table code in newly generated migration file (db/migration/xxxxxxx_drop_table_xyz) like

drop_table :tablename

如果您想在不进行迁移的情况下删除表格,只需打开Rails控制台:

$ rails c

并执行以下命令

ActiveRecord::Base.connection.execute("drop table table_name")

或者您可以使用更简化的命令

ActiveRecord::Migration.drop_table(:table_name)

24
  1. rails g migration drop_users(创建删除用户表的迁移)
  2. 编辑迁移文件
    class DropUsers < ActiveRecord::Migration
      def change
        drop_table :users do |t|
          t.string :name
          t.timestamps
        end
      end
    end
  1. rake db:migrate

17

简单且官方的做法就是这样:

  rails g migration drop_tablename

现在前往你的 db/migrate 目录并查找包含 drop_tablename 作为文件名的文件,将其编辑为以下内容。

    def change
      drop_table :table_name
    end

然后你需要运行

    rake db:migrate 

在您的控制台上。


15

我无法使用迁移脚本让它工作,所以我选择了这个解决方案。在终端中使用Rails控制台:

rails c

类型

ActiveRecord::Migration.drop_table(:tablename)

这对我很有效。这将删除以前的表格。别忘了运行。

rails db:migrate

14

你可以在Rails控制台中简单地删除一个表格。 首先打开控制台。

$ rails c

然后将此命令粘贴到控制台中

ActiveRecord::Migration.drop_table(:table_name)

table_name 替换为您要删除的表名。

您还可以直接从终端删除表。只需进入应用程序的根目录并运行此命令即可。

$ rails runner "Util::Table.clobber 'table_name'"

14

我认为,要完全符合“官方”标准,您需要创建一个新的迁移,并将drop_table放在self.up中。然后,self.down方法应包含重新创建整个表所需的所有代码。可以假设该代码只需从创建迁移时的schema.rb文件中获取。

看起来有点奇怪,因为您要添加创建一个明知道不再需要的表的代码,但这将使所有迁移代码完整和“官方”,对吗?

我刚刚为我需要删除的一个表执行了此操作,但老实说,我没有测试“down”,也不确定为什么要这样做。


1
奇怪的是,看起来我也不得不这样做。 - digitalWestie
9
或者你可以在 self.down 方法中使用 raise ActiveRecord::IrreversibleMigration,这样如果你尝试回滚操作时,至少会给自己一个错误提示或通知。 - Steph Rose
2
我会测试下降,因为否则我会将未经测试的代码引入我的项目。我该如何重用原始迁移的上升方法?我尝试过 CreateMyTable.upActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, X),其中 X 是最初创建表的迁移,但两者都不起作用 - 在这两种方法中,AR 首先检查迁移是否已经应用,并在已应用时静默跳过它。 - Isaac Betesh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接