mysql - remove - rollback migration rails
Recuperar una migraciĆ³n fallida de Rails (9)
¿Cómo revierte una migración de rieles fallidos? Esperaría que rake db:rollback
deshaga la migración fallida, pero no, revierte la migración anterior (la migración fallida menos uno). Y rake db:migrate:down VERSION=myfailedmigration
tampoco funciona. Me he topado con esto algunas veces y es muy frustrante. Aquí hay 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)
vale, vamos a enrollarlo de vuelta:
$ rake db:rollback == AddLevelsToRoles: reverting =============================================== -- remove_column(:roles, :level) -> 0.0778s == AddLevelsToRoles: reverted (0.0779s) ======================================
¿eh? esa fue mi última migración antes de SimpleTest, no la migración fallida. (Y ah, sería bueno si la salida de migración incluyera el número de versión).
Intentemos ejecutar el down para la migración fallida SimpleTest:
$ rake db:migrate:down VERSION=20090326173033 $
No pasa nada y tampoco hay salida. Pero tal vez se ejecutó la migración de todos modos? Entonces, solucionemos el error de sintaxis en la migración SimpleTest e intentemos ejecutarlo nuevamente.
$ 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, la migración: hacia abajo no funcionó. No está fallando, simplemente no se está ejecutando.
No hay forma de deshacerse de esa tabla duplicada que no sea acceder manualmente a la base de datos y eliminarla, y luego ejecutar la prueba. Tiene que haber una mejor manera que eso.
Desafortunadamente, debe limpiar manualmente las migraciones fallidas para MySQL. MySQL no admite cambios en la definición de la base de datos transaccional.
Rails 2.2 incluye migraciones transaccionales para PostgreSQL. Rails 2.3 incluye migraciones transaccionales para SQLite.
Esto realmente no te ayuda para tu problema ahora, pero si tienes una opción de base de datos en proyectos futuros, te recomiendo usar uno con soporte para DDL transaccional porque hace que las migraciones sean mucho más agradables.
Actualización: esto sigue siendo cierto en 2017, en Rails 4.2.7 y MySQL 5.7, reportados por Alejandro Babio en otra respuesta aquí.
Ejecute solo la migración hacia abajo desde la consola:
http://gilesbowkett.blogspot.com/2007/07/how-to-use-migrations-from-console.html (haga clic en su pastie)
En 2015 con Rails 4.2.1 y MySQL 5.7, una migración fallida no se puede arreglar con las acciones de rake estándar que ofrece Rails, como lo fue en 2009.
MySql no admite la reversión de las sentencias DDL (en el manual de MySQL 5.7 ). Y Rails no puede hacer nada con eso.
Además, podemos verificar cómo Rails está haciendo el trabajo: una migración se envuelve en una transacción según cómo responda el adaptador de conexión :supports_ddl_transactions?
. Después de buscar esta acción en rails source (v 4.2.1), descubrí que solo Sqlite3 y PostgreSql admiten transacciones y, por default no es compatible.
Edite la respuesta actual a la pregunta original: una migración de MySQL fallida se debe corregir manualmente.
Estoy de acuerdo en que debes usar PostgreSQL cuando sea posible. Sin embargo, cuando está atrapado con MySQL, puede evitar la mayoría de estos problemas probando primero su migración en su base de datos de prueba:
rake db:migrate RAILS_ENV=test
Puede volver al estado anterior y volver a intentar con
rake db:schema:load RAILS_ENV=test
La manera más fácil de hacerlo es ajustar 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ñaló Luke Francl, "las tablas MyISAM de MySql no admiten transacciones", por lo que puede considerar evitar MySQL en general o al menos MyISAM en particular.
Si está utilizando InnoDB de MySQL, lo anterior funcionará perfectamente. Cualquier error en arriba o abajo retrocederá.
TEN EN CUENTA que algunos tipos de acciones no se pueden revertir a través de transacciones. Por lo general, los cambios en la tabla (descartar una tabla, eliminar o agregar columnas, etc.) no se pueden revertir.
La respuesta de Alejandro Babio arriba proporciona la mejor respuesta actual.
Un detalle adicional que quiero agregar:
Cuando la migración myfailedmigration
falla, no se considera aplicada, y esto se puede verificar ejecutando el myfailedmigration
rake db:migrate:status
, que mostraría un resultado similar al 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
está ejecutando en la migración fallida tendrá que invertirse en el nivel de la base de datos con una alter table assets drop column test;
consulta.
OK, amigos, así es cómo lo hacen en realidad. No sé de qué están hablando las respuestas anteriores.
- Averigua qué parte de la migración ascendente funcionó. Comenta ésos.
- También comente / elimine la parte de la migración que se rompió.
- Ejecute la migración nuevamente. Ahora completará las partes no rotas de la migración, omitiendo las partes que ya se han realizado.
- Descomente los bits de la migración que comentó en el paso 1.
Puede migrar hacia abajo y hacia atrás otra vez si desea verificar que lo tiene ahora mismo.
Para ir a una versión especificada simplemente use:
rake db:migrate VERSION=(the version you want to go to)
Pero si una migración falla en parte, primero tendrá que limpiarla. Una forma sería:
- edite el método
down
de la migración para deshacer la parte delup
que funcionó - migrar de nuevo al estado anterior (donde comenzó)
- corrige la migración (incluso deshacer los cambios en el
down
) - Inténtalo de nuevo
Tuve un error tipográfico (en "add_column"):
def self.up
add_column :medias, :title, :text add_colunm :medias, :enctype, :text
fin
def self.down
remove_column :medias, :title remove_column :medias, :enctype
fin
y luego su problema (no se puede deshacer parcialmente la migración fallida). después de algunos errores de Google, ejecuté esto:
def self.up
remove_column :medias, :title add_column :medias, :title, :text add_column :medias, :enctype, :text
fin
def self.down
remove_column :medias, :title remove_column :medias, :enctype
fin
como puedes ver, acabo de agregar la línea de corrección a mano, y luego la eliminé nuevamente, antes de registrarla.