Migraciones de rieles: ¿comprobar la existencia y continuar?

80

Estaba haciendo este tipo de cosas en mis migraciones:

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

pero resulta que, si bien esto funciona para SQLite, no funciona para PostgreSQL . Parece que si add_column explota, incluso si se detecta la excepción, la transacción está muerta y, por lo tanto, la migración no puede realizar ningún trabajo adicional.

¿Hay alguna forma específica que no sea de DB para verificar si ya existe una columna o tabla? De no ser así, ¿hay alguna forma de hacer que mi bloque de rescate funcione realmente?

Dan Rosenstark
fuente
Es necesario mencionar que la migración condicional conduce a problemas con la reversión debido al hecho de que en la etapa de reversión no se conocen las condiciones durante la migración hacia adelante
oklas
Solo haga la parte no opcional en la reversión
Dan Rosenstark

Respuestas:

175

A partir de Rails 3.0 y posteriores, puede utilizarlo column_exists?para comprobar la existencia de una columna.

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

También hay una table_exists?función, que se remonta a Rails 2.1.

Tobias Cohen
fuente
¿Se considera una buena práctica comprobar si existe una columna / tabla antes de agregarla / crearla? (Sé, por supuesto, que depende del problema en las manos)
Aldo 'xoen' Giambelluca
4
¿Funciona esto con reversiones si lo defino en el método de cambio?
dardub
1
Sí, la reversión sería un problema ... no estamos seguros de si deberíamos eliminar la columna o no ... ya que no estamos registrando el estado anterior.
songyy
8

O incluso más corto

add_column :statuses, :hold_reason, :string unless column_exists? :statuses, :hold_reason
SG 86
fuente
esto sería un comentario sobre la otra respuesta, no una respuesta. Gracias.
Dan Rosenstark
4

Para Rails 2.X , puede verificar la existencia de columnas con lo siguiente:

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

Si devuelve nil, no existe tal columna. Si devuelve un Fixnum, entonces la columna existe. Naturalmente, puede colocar parámetros más selectivos entre {...}si desea identificar una columna por algo más que su nombre, por ejemplo:

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

(esta respuesta se publicó por primera vez en ¿Cómo escribir migraciones condicionales en rieles? )

JellicleCat
fuente
0

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

Denis Neverov
fuente