web-dev-qa-db-fra.com

Comment ignorez-vous les migrations ayant échoué? (rake db: migrate)

Je n'arrive pas à trouver une option ou quoi que ce soit qui me permette d'ignorer les migrations.

Je sais ce que vous pensez: "vous ne devriez jamais avoir à faire ça ..."

Je dois ignorer une migration qui modifie des enregistrements d'utilisateurs spécifiques qui n'existent pas dans ma base de développement. Je ne veux pas changer la migration car elle ne fait pas partie de la source avec laquelle je suis supposée travailler. Existe-t-il un moyen d'ignorer une migration ou les migrations échouées?

Merci d'avance!

35
hmind

Je pense que vous devriez corriger les migrations incriminées pour qu'elles soient moins fragiles. Je suppose que deux déclarations if et peut-être une rescue seraient suffisantes.

Toutefois, si la résolution des migrations n’est pas vraiment une option, vous pouvez la simuler de différentes manières. Tout d'abord, vous pouvez simplement commenter les méthodes de migration, exécuter rake db:migrate, puis supprimer le commentaire (ou rétablir) la migration incriminée.

Vous pouvez également le simuler dans la base de données, mais ce type de chicane n'est pas recommandé à moins que vous ne sachiez ce que vous faites et que cela ne vous dérange pas de corriger manuellement les choses lorsque vous faites (inévitablement) une erreur. Il y a une table dans votre base de données appelée schema_migrations qui a une seule colonne varchar(255) appelée version; db:migrate utilise cette table pour savoir quelles migrations ont été appliquées. Il vous suffit d'insérer la valeur version appropriée et rake db:migrate pensera que la migration a été effectuée. Recherchez le fichier de migration incriminé:

db/migrate/99999999999999_XXXX.rb

puis allez dans votre base de données et dites:

insert into schema_migrations (version) values ('99999999999999');

99999999999999 est bien entendu le numéro du nom de fichier de la migration. Ensuite, exécuter rake db:migrate devrait ignorer cette migration.

J'irais avec la deuxième option avant la troisième, je n'inclus que l'option "pirater schema_versions" pour la complétude.

56
mu is too short

J'ai eu un problème où j'avais une migration pour ajouter un tableau qui existait déjà, alors dans mon cas, je devais aussi ignorer cette migration, car j'avais l'erreur

SQLite3::SQLException: table "posts" already exists: CREATE TABLE "posts"

Je me suis contenté de commenter le contenu de la méthode create table, d'exécuter la migration, puis de le supprimer. C'est un moyen manuel de contourner le problème, mais cela a fonctionné. Voir ci-dessous:

class CreatePosts < ActiveRecord::Migration
  def change
    # create_table :posts do |t|
    #   t.string :title
    #   t.text :message
    #   t.string :attachment
    #   t.integer :user_id
    #   t.boolean :comment
    #   t.integer :phase_id

    #   t.timestamps
    # end
  end
end
16
user1647964

C'est un bon moyen de le faire pour des erreurs uniques. 

db:migrate:up VERSION=my_version

Cela exécutera les actions "up" d'une migration spécifique. (Il y a aussi le contraire si vous en avez besoin, remplacez simplement "up" par "down".) Ainsi, vous pouvez exécuter la migration future qui permet à l'ancienne (que vous devez ignorer) de fonctionner la migration devant elle de manière sélective.

Je crois aussi que vous pouvez refaire les migrations de cette façon:

rake db:migrate:redo VERSION=my_version 

Je n'ai pas essayé cette méthode personnellement, donc YMMV.

15
John

Si vous devez le faire, les migrations de votre application sont gâchées!

Insère toutes les migrations manquantes:

def insert(xxx)
  ActiveRecord::Base.connection.execute("insert into schema_migrations (version) values (#{xxx})") rescue nil
end

files = Dir.glob("db/migrate/*")
files.collect { |f| f.split("/").last.split("_").first }.map { |n| insert(n) }
7
Dorian

parfois, il est nécessaire de remplir à nouveau la table schema_migrations avec les migrations sont définitivement correctes ... UNIQUEMENT À CET EFFET i a créé cette méthode

def self.insert_missing_migrations(stop_migration=nil)
  files = Dir.glob("db/migrate/*")
  timestamps = files.collect{|f| f.split("/").last.split("_").first}
  only_n_first_migrations = timestamps.split(stop_migration).first

  only_n_first_migrations.each do |version|
    sql = "insert into `schema_migrations` (`version`) values (#{version})"
    ActiveRecord::Base.connection.execute(sql) rescue nil
  end
end

vous pouvez le copier-coller dans le modèle de votre choix et l'utiliser depuis la console

YourModel.insert_missing_migrations("xxxxxxxxxxxxxx")

(ou d'une autre manière)

"xxxxxxxxxxxxxx" - correspond à l'horodatage de la migration avant lequel vous souhaitez arrêter l'insertion (vous pouvez le laisser vide)

!!! utilisez-le uniquement si vous comprenez absolument quel résultat vous obtiendrez !!!

1
okliv

Au lieu de passer la migration, vous pouvez rendre votre migration intelligente, en y ajoutant un IF, de sorte que vous puissiez vérifier les "utilisateurs spécifiques"

1
Alessandro DS

Pour ignorer toutes les migrations en attente, exécutez ceci dans votre terminal:

echo "a = [" $(Rails db:migrate:status | grep "down" | grep -o '[0-9]\{1,\}' | tr '\n' ', ') "];def insert(b);ActiveRecord::Base.connection.execute(\"insert into schema_migrations (version) values (#{b})\") rescue nil;end;a.map { |b| insert(b)}" | xclip

(Pour macOS, utilisez pbcopy au lieu de xclip) 

Puis CTRL-V le résultat dans la console Rails:

a = [ 20180927120600,20180927120700 ];def insert(b);ActiveRecord::Base.connection.execute("insert into schema_migrations (version) values (#{b})") rescue nil;end;a.map { |b| insert(b)}

Et appuyez sur ENTER. 

Vous pouvez modifier la liste des migrations que vous souhaitez ignorer en les supprimant du tableau a avant d'exécuter la ligne.

0
Timur Nugmanov