Миграции Rails: проверить существование и продолжить?

80

Я делал такие вещи в своих миграциях:

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

но оказывается, что, хотя это работает для SQLite, это не работает для PostgreSQL . Похоже, что если add_column взорвется, даже если исключение перехвачено , транзакция мертва, и поэтому миграция не может выполнять дополнительную работу.

Есть ли какие -либо способы, не связанные с БД, чтобы проверить, существует ли уже столбец или таблица? Если это не удается, есть ли способ заставить мой спасательный блок действительно работать?

Дэн Розенстарк
источник
Следует отметить, что условная миграция приводит к проблемам с откатом из-за того, что на этапе отката неизвестно, какие условия были во время прямой миграции
oklas
Делайте

Ответы:

175

Начиная с Rails 3.0 и более поздних column_exists?версий вы можете использовать для проверки существования столбца.

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

Также есть table_exists?функция, восходящая к Rails 2.1.

Тобиас Коэн
источник
Считается ли лучшей практикой проверить, существует ли столбец / таблица, прежде чем добавлять / создавать ее? (Я знаю, конечно, это зависит от проблемы в руках)
Альдо 'xoen' Джамбеллука
4
Работает ли это с откатами, если я определю это в методе изменения?
dardub
1
Да, откат был бы проблемой ... мы не уверены, следует ли нам удалять столбец или нет ... поскольку мы не записываем предыдущее состояние.
songyy
8

Или даже короче

add_column :statuses, :hold_reason, :string unless column_exists? :statuses, :hold_reason
ИК 86
источник
это будет комментарий к другому ответу, а не ответ. Благодарю.
Дэн Розенстарк
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 }

(этот ответ впервые был опубликован в разделе Как писать условные миграции в рельсах? )

JellicleCat
источник
0

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

Денис Неверов
источник