Rails 迁移:检查存在并继续?

Posted

技术标签:

【中文标题】Rails 迁移:检查存在并继续?【英文标题】:Rails Migrations: Check Existence and Keep Going? 【发布时间】:2010-12-11 08:11:21 【问题描述】:

我在迁移中做这种事情:

add_column :statuses, :hold_reason, :string rescue puts "column already added"

但事实证明,虽然这适用于 SQLite,但不适用于 PostgreSQL。似乎如果 add_column 爆炸了,即使捕获到异常,事务也已死亡,因此迁移无法做任何额外的工作。

是否有任何非数据库特定方法来检查列或表是否已存在?如果做不到这一点,有没有办法让我的救援块真正起作用?

【问题讨论】:

需要说明的是,条件迁移会导致回滚问题,因为在回滚阶段不知道前向迁移的条件是什么 只做回滚中的非可选部分 【参考方案1】:

Rails 6.1+:

add_column :statuses, :hold_reason, :string, if_not_exists: true

https://github.com/rails/rails/pull/38352/files

Rails

add_column :statuses, :hold_reason, :string unless column_exists?(:statuses, :hold_reason)

【讨论】:

【参考方案2】:

add_column :statuses, :hold_reason, :string unless Status.column_names.include?("hold_reason")

【讨论】:

【参考方案3】:

甚至更短

add_column :statuses, :hold_reason, :string unless column_exists? :statuses, :hold_reason

【讨论】:

这将是对另一个答案的评论,而不是答案。谢谢。【参考方案4】:

对于 Rails 2.X,您可以使用以下内容检查列是否存在:

columns("[table-name]").index |col| col.name == "[column-name]"

如果它返回 nil,则不存在这样的列。如果它返回一个 Fixnum,那么该列确实存在。当然,如果您想通过不仅仅是名称来识别列,您可以在 ... 之间放置更多选择性参数,例如:

 |col| col.name == "foo" and col.sql_type == "tinyint(1)" and col.primary == nil 

(这个答案首先发布在How to write conditional migrations in rails?)

【讨论】:

【参考方案5】:

从 Rails 3.0 及更高版本开始,您可以使用 column_exists? 检查列是否存在。

unless column_exists? :statuses, :hold_reason
  add_column :statuses, :hold_reason, :string
end

还有一个 table_exists? 函数,它可以追溯到 Rails 2.1。

【讨论】:

在添加/创建之前检查列/表是否存在是否被认为是最佳实践? (我当然知道这取决于手中的问题) 如果我在 change 方法中定义它,这是否适用于回滚? 是的,回滚将是一个问题...我们不确定是否应该删除该列...因为我们没有记录以前的状态。

以上是关于Rails 迁移:检查存在并继续?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Rails 迁移中添加检查约束?

Rails 6:从表单输入动态创建/切换/迁移数据库

Rails 迁移:重命名表上的索引

在 Rails 中恢复特定的旧迁移,而不恢复以后的迁移

如何通过 Rails 迁移克隆数据库表?

在 Postgres 迁移后,Rails 写入时间增加了 100%