Deshacer una migración rieles fallado
-
22-08-2019 - |
Pregunta
¿Cómo revertir una migración rieles fallado? Yo esperaría que rake db:rollback
desharía la migración fallado, pero no, deshace la migración anterior (la migración no menos uno). Y rake db:migrate:down VERSION=myfailedmigration
no funciona bien. He encontré con esto unas cuantas veces y es muy frustrante. Aquí está una prueba simple que hice para duplicar el problema:
class SimpleTest < ActiveRecord::Migration
def self.up
add_column :assets, :test, :integer
# the following syntax error will cause the migration to fail
add_column :asset, :test2, :integer
end
def self.down
remove_column :assets, :test
remove_column :assets, :test2
end
end
resultado:
== SimpleTest: migrating ===================================================== -- add_column(:assets, :test, :integer) -> 0.0932s -- add_column(:asset, :error) rake aborted! An error has occurred, all later migrations canceled: wrong number of arguments (2 for 3)
Muy buena opción rollo de nuevo:
$ rake db:rollback == AddLevelsToRoles: reverting =============================================== -- remove_column(:roles, :level) -> 0.0778s == AddLevelsToRoles: reverted (0.0779s) ======================================
¿eh? que fue mi última migración antes de SimpleTest, no la migración fallado. (Y, oh, sería bueno si la salida de la migración incluido el número de versión.)
Así que vamos a intentar ejecutar el abajo para la migración SimpleTest fallado:
$ rake db:migrate:down VERSION=20090326173033 $
No pasa nada, y no hay salida tampoco. Pero tal vez corrió la migración de todos modos? Por lo que permite solucionar el error de sintaxis en la migración SimpleTest, y tratar de volver a ejecutarlo.
$ rake db:migrate:up VERSION=20090326173033 == SimpleTest: migrating ===================================================== -- add_column(:assets, :test, :integer) rake aborted! Mysql::Error: Duplicate column name 'test': ALTER TABLE `assets` ADD `test` int(11)
Nop. Obviamente, el migran: abajo no funcionaba. No es no, simplemente no está en ejecución.
No hay manera de librarse de esa tabla duplicada otra que ir manualmente en la base de datos y su eliminación, y después de ejecutar la prueba. Tiene que haber una manera mejor que eso.
Solución
Por desgracia, debe limpiar manualmente las migraciones fallidas para MySQL. MySQL no soporta cambios de definición de bases de datos transaccionales.
Barras de 2.2 incluye migraciones transaccionales para PostgreSQL. Carriles 2,3 incluye migraciones transaccionales para SQLite.
Esto en realidad no le ayuda para su problema en este momento, pero si usted tiene una opción de la base de datos sobre proyectos futuros, le recomiendo usar uno con soporte para DDL transaccional, ya que hace migraciones mucho más agradable.
Actualizar - esto sigue siendo cierto en 2017, en los carriles 4.2.7 y MySQL 5.7, reportados por Alejandro Babio en otra respuesta aquí
.Otros consejos
Para ir a una versión especificada sólo tiene que utilizar:
rake db:migrate VERSION=(the version you want to go to)
Pero si un error en la migración forma parte, tendrá que limpiar primero. Una forma sería la siguiente:
- editar el método
down
de la migración a simplemente deshacer la parte de laup
que trabajó - migrar volver al estado anterior (punto de partida)
- fijar la migración (incluyendo deshacer los cambios en el
down
) - intentarlo de nuevo
OK, gente, aquí es cómo hacerlo en realidad. No sé lo que las respuestas anteriores están hablando.
- Figura saber qué parte de la migración hasta trabajó. Comentar ésos hacia fuera.
- También comente / quitar la parte de la migración que se rompió.
- Ejecutar de nuevo la migración. Ahora va a completar las partes no roto de la migración, omitiendo las partes que ya se han hecho.
- Elimine los bits de la migración Ha comentado a cabo en el paso 1.
Puede migrar hacia abajo y una copia de seguridad de nuevo si desea verificar que lo tienes en este momento.
Estoy de acuerdo que se debe utilizar PostgreSQL cuando sea posible. Sin embargo, cuando le pegan con MySQL, puede evitar la mayoría de estos problemas al tratar la migración de su base de datos de prueba primero:
rake db:migrate RAILS_ENV=test
Puede volver al estado anterior e inténtelo de nuevo con
rake db:schema:load RAILS_ENV=test
En 2015, con Rails 4.2.1 y MySQL 5.7, una migración fallida no se puede solucionar con acciones rastrillo estándar que proporcionan los carriles, como lo fue en 2009.
MySQL no soporta la reversión de statments DDL (en MySQL 5.7 Manual ). Rieles y no pueden hacer nada con eso.
Además, podemos comprobar cómo los carriles está haciendo el trabajo: Una migración es envuelto en una transacción dependiendo de cómo responden adaptador de conexión a :supports_ddl_transactions?
. Después de una búsqueda de esta acción en los carriles de la fuente (v 4.2.1), encontré que sólo Sqlite3 y PostgreSql soporta transacciones, y por no se admite por defecto él.
Editar Por lo tanto la respuesta actual a la pregunta original:. Una migración de MySQL no debe fijarse manualmente
La forma más fácil de hacer esto es envolver todas sus acciones en una transacción:
class WhateverMigration < ActiveRecord::Migration
def self.up
ActiveRecord::Base.transaction do
...
end
end
def self.down
ActiveRecord::Base.transaction do
...
end
end
end
Como se señaló Lucas Francl, "MySql [ 's tablas MyISAM no] transacciones de apoyo." - que es por qué es posible considerar evitar MySQL en general, o al menos MyISAM, en particular
Si está utilizando InnoDB de MySQL, y luego lo anterior funcionará bien. Cualquier error en arriba o hacia abajo se echarse atrás.
ser conscientes algunos tipos de acciones no pueden ser revertidos a través de transacciones. Generalmente, los cambios de mesa (dejando caer una mesa, la eliminación o la adición de columnas, etc.) no se pueden revertir.
Ejecutar sólo la migración hacia abajo desde la consola:
http: //gilesbowkett.blogspot .com / 2007/07 / cómo-a-uso-migraciones-de-console.html (clic a través de su pastie)
Yo tenía un error tipográfico (en "add_column"):
def self.up
add_column :medias, :title, :text add_colunm :medias, :enctype, :text
end
def self.down
remove_column :medias, :title remove_column :medias, :enctype
end
y entonces su problema (no puede deshacer la migración en parte fallado). después de algunos no buscando en Google me encontré esto:
def self.up
remove_column :medias, :title add_column :medias, :title, :text add_column :medias, :enctype, :text
end
def self.down
remove_column :medias, :title remove_column :medias, :enctype
end
como se puede ver me acaba de agregar la línea de corrección a mano, y luego se retira de nuevo, antes de que yo lo haya facturado.
La respuesta de Alejandro Babio anterior proporciona la mejor respuesta actual.
Un detalle adicional Quiero añadir:
Cuando la migración myfailedmigration
falla, no se considera en su aplicación, y esto puede ser verificada mediante la ejecución de rake db:migrate:status
, que mostraría una salida similar a la siguiente:
$ rake db:migrate:status
database: sample_app_dev
Status Migration ID Migration Name
--------------------------------------------------
up 20130206203115 Create users
...
...
down 20150501173156 Test migration
El efecto residual de add_column :assets, :test, :integer
siendo ejecutado en la migración no tendrá que ser revertido a nivel de base de datos con una consulta alter table assets drop column test;
.