web-dev-qa-db-fra.com

Comment rendez-vous remove_column réversible?

J'ai une migration qui supprime une colonne:

def change
  remove_column :foos, :bar, :boolean
end

Quand j'essaie de rake db:rollback cette migration, j'obtiens l'erreur suivante:

remove_column is only reversible if given a type.

La documentation ActiveRecord :: Migration indique que ce qui suit est la signature de remove_column:

remove_column(table_name, column_name, type, options)

Donc, mon type dans ce cas devrait être :boolean, et je m'attends à ce que la migration soit réversible. Qu'est-ce que je rate?

Je peux certainement décomposer cela en une migration up et down pour éviter ce problème, mais j'aimerais comprendre pourquoi la syntaxe change ne fonctionne pas dans ce cas .

44
user1454117

Ajouter simplement le 3ème argument (la colonne: type) au remove_column rend cette migration réversible. Le code original de l'OP a donc fonctionné, comme dans:

remove_column :foos, :bar, :boolean

Le reste de cette réponse était une tentative de découvrir pourquoi cette méthode n'aurait pas fonctionné, mais l'OP a fini par la faire fonctionner.


Je vois des informations quelque peu contraires dans la documentation de ActiveRecord :: Migration :

Certaines commandes comme remove_column ne peuvent pas être inversées. Si vous souhaitez définir comment monter et descendre dans ces cas, vous devez définir les méthodes de montée et de descente comme précédemment.

Pour une liste des commandes réversibles, veuillez consulter ActiveRecord :: Migration :: CommandRecorder.

Et cela depuis ActiveRecord :: Migration :: CommandRecorder :

ActiveRecord :: Migration :: CommandRecorder enregistre les commandes effectuées pendant une migration et sait comment inverser ces commandes. Le CommandRecorder sait comment inverser les commandes suivantes:

add_column

add_index

add_timestamps

create_table

create_join_table

remove_timestamps

rename_column

rename_index

rename_table

Quoi qu'il en soit, il semble que cette documentation soit obsolète ... Creuser dans la source sur github :

La méthode qui vous cause du chagrin est:

def invert_remove_column(args)
  raise ActiveRecord::IrreversibleMigration, "remove_column is only reversible if given a type." if args.size <= 2
  super
end

J'ai donné un coup de feu ... configurer une migration sur mon Rails 4.1.2 application et la migration a fonctionné dans les deux sens - de haut en bas. Voici ma migration:

class TestRemoveColumn < ActiveRecord::Migration
  def change
    remove_column :contacts, :test, :boolean
  end
end

J'ai aussi essayé avec le :boolean argument manquant et a la même erreur que celle dont vous parlez. Êtes-vous sûr que vous êtes sur la version finale de Rails 4.1.2 - pas l'un des candidats à la sortie? Si vous l'êtes, je vous suggère de mettre un binding.pry dans le Rails source pour le invert_remove_column méthode pour inspecter la liste des arguments et voir ce qui se passe. Pour ce faire, exécutez simplement bundle open activerecord puis explorez pour: lib/active_record/migration/command_recorder.rb: 128.

75
pdobb

Au lieu d'utiliser change, vous utilisez les méthodes up et down pour votre migration:

def up
  remove_column :foos, :bar
end

def down
  add_column :foos, :bar, :boolean
end
2
bratsche