46 votes

Rails : Est-il mauvais d'avoir une migration irréversible ?

Quand est-il acceptable de lever une exception ActiveRecord::IrreversibleMigration dans la méthode self.down d'une migration ? Quand faut-il prendre la peine d'implémenter l'inverse de la migration ?

59voto

vladr Points 34562

Si vous avez affaire à des systèmes de production alors oui, c'est très mauvais. S'il s'agit de votre propre projet, alors tout est permis (si rien d'autre, ce sera une expérience d'apprentissage :) bien qu'il y ait de fortes chances que tôt ou tard, même dans le cadre d'un projet, vous vous retrouviez à avoir mis une croix sur une migration inverse pour devoir annuler cette migration quelques jours plus tard, que ce soit via rake ou manuellement).

Dans un scénario de production, vous devez toujours faire l'effort d'écrire et de tester une migration réversible dans l'éventualité où vous le passez en production, puis découvrez un bug qui vous oblige à revenir en arrière (code y schéma) à une révision antérieure (en attendant un correctif non trivial -- et un système de production autrement inutilisable).

Les migrations inversées peuvent être triviales (suppression des colonnes ou des tables qui ont été ajoutées pendant la migration, et/ou modification des types de colonnes, etc.) ou un peu plus complexes ( execute de JOIN ed INSERT ou UPDATE ), mais rien n'est complexe au point de justifier de le "balayer sous le tapis". Au moins, le fait de vous forcer à réfléchir à des moyens de réaliser des migrations inverses peut vous donner un nouvel aperçu du problème que votre migration vers l'avant est en train de résoudre.

Vous pouvez parfois vous trouver dans une situation où une migration vers l'avant supprime une fonctionnalité, ce qui entraîne l'élimination de données de la base de données. Pour des raisons évidentes, la migration inverse ne peut pas ressusciter les données supprimées. Bien que l'on puisse, dans de tels cas, recommander que la migration vers l'avant sauvegarde automatiquement les données ou les conserve dans l'éventualité d'un retour en arrière comme alternative à un échec pur et simple (sauvegarder vers yml ), vous n'êtes pas obligé de le faire, car le temps nécessaire pour tester une telle procédure automatisée pourrait dépasser le temps nécessaire pour restaurer les données manuellement (si le besoin s'en fait sentir). Mais même dans de tels cas, au lieu de simplement échouer vous pouvez toujours faire la migration inverse conditionnellement et temporairement échouer dans l'attente d'une action de l'utilisateur (c'est-à-dire tester l'existence d'une table requise qui doit être restaurée manuellement ; si elle est absente, le message "J'ai échoué car je ne peux pas recréer la table XYZ du néant ; restaurer manuellement la table XYZ de la sauvegarde, alors courez-moi à nouveau, et je ne vous laisserai pas tomber !")

29voto

Mark Lanett Points 161

Si vous détruisez des données, vous pouvez d'abord en faire une sauvegarde. Par exemple.

def self.up
  # create a backup table before destroying data 
  execute %Q[create table backup_users select * from users]  
  remove_column :users, :timezone
end  

def self.down
  add_column :users, :timezone, :string  
  execute %Q[update users U left join backup_users B on (B.id=U.id) set U.timezone = B.timezone]
  execute %Q[drop table backup_users]  
end

8voto

jdl Points 12272

Dans un scénario de production, vous devriez toujours faire l'effort d'écrire et de tester une migration réversible dans l'éventualité où vous l'effectuez en production, puis découvrez un bogue qui vous oblige à revenir (code et schéma) à une révision antérieure (dans l'attente d'un correctif non trivial - et d'un système de production inutilisable).

La migration réversible est une bonne chose pour le développement et la mise en place, mais si le code est bien testé, il devrait être extrêmement rare que vous souhaitiez effectuer une migration vers le bas en production. J'intègre dans mes migrations une IrreversibleMigration automatique en mode production. Si j'avais vraiment besoin d'inverser une modification, je pourrais utiliser une autre migration "up" ou supprimer l'exception. Mais cela semble peu convaincant. Tout bogue susceptible de provoquer un scénario aussi désastreux est un signe que le processus d'assurance qualité est sérieusement déréglé.

3voto

rfunduk Points 15267

Avoir l'impression d'avoir besoin d'une migration irréversible est probablement un signe que vous avez de plus gros problèmes qui se profilent. Peut-être que des détails précis pourraient aider ?

Quant à votre deuxième question : Je fais toujours l'effort d'écrire l'inverse des migrations. Bien sûr, I n'écrivent pas réellement le .down TextMate l'insère automatiquement lors de la création de l'étiquette. .up .

3voto

Tom Maeckelberghe Points 1058

Migration réversible des données permet de créer facilement des migrations de données réversibles à l'aide de fichiers yaml.

class RemoveStateFromProduct < ActiveRecord::Migration
  def self.up
    backup_data = []
    Product.all.each do |product|
      backup_data << {:id => product.id, :state => product.state}
    end
    backup backup_data
    remove_column :products, :state
  end
  def self.down
    add_column :products, :state, :string
    restore Product
  end
end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X