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

我在迁徙的时候做过这样的事:

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

但结果是 虽然这适用于 SQLite,但不适用于 PostgreSQL。似乎是这样的,如果 add _ column 爆炸,即使抓住了例外,事务就会死亡,因此迁移不能执行任何额外的工作。

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

36952 次浏览

As of Rails 3.0 and later, you can use column_exists? to check for the existance of a column.

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

There's also a table_exists? function, which goes as far back as Rails 2.1.

For Rails 2.X, you can check the existence of columns with the following:

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

If it returns nil, no such column exists. If it returns a Fixnum, then the column does exist. Naturally, you can put more selective parameters between the {...} if you want to identify a column by more than just its name, for example:

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

(this answer first posted on How to write conditional migrations in rails?)

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

Or even shorter

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

Rails 6.1+:

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

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

Rails < 6.1:

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