我在我的迁移中做了这样的事情:
add_column :statuses, :hold_reason, :string rescue puts "column already added"
但事实证明,尽管这对SQLite有效,但它对PostgreSQL无效。似乎如果add_column出现问题,即使捕获了异常,事务也会失败,因此迁移无法执行任何其他工作。
是否有任何非数据库特定的方法来检查列或表是否已存在?如果失败,是否有任何方法使我的异常处理块真正起作用?
我在我的迁移中做了这样的事情:
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。
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)
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 }
(这篇回答最初发布在如何在Rails中编写条件迁移?)
在Rails中,可以使用条件迁移来实现只在特定情况下才运行迁移。可以通过在迁移文件中嵌入Ruby代码来实现此目的。 例如,以下是一个示例迁移,仅在当前Rails环境为"production"时才执行:
class AddIndexToUsersEmail < ActiveRecord::Migration
def change
add_index :users, :email
add_index :users, :username if Rails.env.production?
end
end
unless Status.column_names.include?("hold_reason")
,add_column :statuses, :hold_reason, :string