2010-09-28 5 views
1

J'ai une migration qui est la rupture au milieu d'un couple de changements de schéma. Quand il se casse une exception est levée et rake db: migrate quitte, laissant ma base de données dans un état à moitié migré.Utiliser db: migrate: refaire lors de la manipulation correctement exceptions de modifications de schéma

Comment puis-je le configurer de sorte que la migration revient automatiquement seulement les changements qui ont été exécutées à ce jour? Je voudrais le faire globalement en mode développement. Sûrement quelqu'un là-bas a une meilleure façon que l'intégration de chaque AR::Migration::ClassMethod successives dans un bloc begin; rescue =>e opposite_action; end.

Peut-être un exemple courant est en ordre:

#2010010100000000_made_a_typo.rb 
class MadeATypo < ActiveRecord::Migration 

    def self.up 
     rename_column :birds, :url, :photo_file_name 
     rename_column :birds, :genius, :species #typo on :genius => :genus 
    end 
    def self.down 
     rename_column :birds, :photo_file_name, :url 
     rename_column :birds, :species, :genius 
    end 
end 

Cette migration échoue sur la deuxième ligne avec le « génie de colonne est introuvable », mais pas enregistrer le numéro de la migration dans la table schema_migrations. Je voudrais si elle a appelé

rename_column :birds, :photo_file_name, :url #this is a revert of the first line

avant que l'exception a été adoptée sur MadeATypo.up.

Les réponses aux commentaires:

Je comprends que MySQL pourrait ne pas avoir le soutien pour les transactions DDL, je suis à la recherche d'une solution plus au niveau de l'application qui (probablement) utilise AR :: migration elle-même. Il est certain que quelqu'un a créé un plugin qui capture les appels de méthode au AR: M: ClassMethods principal et peut les rembobiner dans la plupart des cas si une exception survient pendant une migration.

Répondre

0

Je ne sais pas de toute façon de le faire actuellement, mais le code pour les migrations réversibles à venir à Rails 3.1 semble être une bonne base pour construire cette fonction. Voir ces liens:

La façon dont je pense que vous pourriez mettre en œuvre est d'exécuter la migration contre l'enregistreur (comme dans https://github.com/rails/rails/commit/47017bd1697d6b4d6780356a403f91536eacd689#L0R337), puis revenir à la connexion en direct et exécuter l'enregistreur en avant une commande à la fois, le suivi de combien ont terminé. Tout ce dont vous avez besoin est alors d'enrouler cette boucle d'exécution en avant dans une begin-rescue-end qui exécute autant de commandes inverses que si vous avez exécuté avec succès des commandes forward, s'il y a une exception.

+0

C'est génial. Je vous remercie. –

1

Je n'ai pas une solution, mais le problème principal est que les déclarations DDL ne peuvent pas être transactioned (au moins dans MySQL, je ne sais pas si c'est une chose générale).

Ainsi, parce que les migrations sont traitées comme des actions atomiques haut/bas, il n'y a pas moyen facile de défaire « la moitié » une migration - il est difficile de trouver quelles parties du down correspondent à quelles parties du up

+0

correcte. Je crois que vous avez une bonne compréhension du problème, merci pour le retraitement. En aparté, lorsque vous utilisez « DDL » de cette façon - Vous parlez de CREATE TABLE et analogues, ou est-ce un railsism pour certaines des méthodes de migration de activerecord? –

+0

En fait, je pense que je me trompe à ce sujet de toute façon. Ma source que je lisais plus tôt aujourd'hui était http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html (voir 'Caveats' en bas) - qui indique seulement que les instructions DDL ne peuvent pas être gérées comme ActiveRecord émule ** les transactions ** imbriquées. Donc, cela invalide la plupart de ma réponse vraiment: -/ – Gareth

+0

Non, la réponse est correcte. MySQL ne peut pas gérer les modifications DDL transactionnelles. PostgreSQL en revanche, si une migration échoue à mi-chemin, le DB est laissé inchangé. Cela étant dit, essayez d'avoir des migrations plus petites: si vous faites un seul changement par migration, vous ne pouvez pas laisser votre DB dans un état incohérent: un seul changement est survenu, et puisqu'il a échoué, il peut être réessayé. –

Questions connexes