我在迁移中做了这样的事情:
add_column :statuses, :hold_reason, :string rescue puts "column already added"
但事实证明,虽然这适用于 SQLite,但它不适用于 PostgreSQL。看起来如果 add_column 爆炸了,即使捕获到异常,事务也已死,因此迁移无法做任何额外的工作。
是否有任何非数据库特定的方法来检查列或表是否已经存在?如果做不到这一点,有没有办法让我的救援块真正起作用?
从 Rails 3.0 及更高版本开始,您可以使用 column_exists?
检查列是否存在。
unless column_exists? :statuses, :hold_reason
add_column :statuses, :hold_reason, :string
end
还有一个 table_exists?
函数,它可以追溯到 Rails 2.1。
导轨 6.1+:
add_column :statuses, :hold_reason, :string, if_not_exists: true
https://github.com/rails/rails/pull/38352/files
导轨 < 6.1:
add_column :statuses, :hold_reason, :string unless column_exists?(:statuses, :hold_reason)
甚至更短
add_column :statuses, :hold_reason, :string unless column_exists? :statuses, :hold_reason
对于 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?)
add_column :statuses, :hold_reason, :string unless Status.column_names.include?("hold_reason")