Comment renommer une colonne de base de données dans une migration Ruby on Rails?

1452

J'ai mal nommé une colonne hased_passwordau lieu de hashed_password.

Comment mettre à jour le schéma de la base de données, en utilisant la migration pour renommer cette colonne?

user1994764
la source

Réponses:

2309
rename_column :table, :old_column, :new_column

Vous souhaiterez probablement créer une migration distincte pour ce faire. (Renommez FixColumnNamecomme vous voulez.):

script/generate migration FixColumnName
# creates  db/migrate/xxxxxxxxxx_fix_column_name.rb

Modifiez ensuite la migration pour faire votre volonté:

# db/migrate/xxxxxxxxxx_fix_column_name.rb
class FixColumnName < ActiveRecord::Migration
  def self.up
    rename_column :table_name, :old_column, :new_column
  end

  def self.down
    # rename back if you need or do something else or do nothing
  end
end

Pour l'utilisation de Rails 3.1:

Alors que les méthodes upet downs'appliquent toujours, Rails 3.1 reçoit une changeméthode qui "sait comment migrer votre base de données et l'inverser lorsque la migration est annulée sans avoir besoin d'écrire une méthode distincte".

Voir « Migrations d'enregistrements actifs » pour plus d'informations.

rails g migration FixColumnName

class FixColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

S'il vous arrive d'avoir un tas de colonnes à renommer, ou quelque chose qui aurait nécessité de répéter le nom de la table encore et encore:

rename_column :table_name, :old_column1, :new_column1
rename_column :table_name, :old_column2, :new_column2
...

Vous pouvez utiliser change_tablepour garder les choses un peu plus propres:

class FixColumnNames < ActiveRecord::Migration
  def change
    change_table :table_name do |t|
      t.rename :old_column1, :new_column1
      t.rename :old_column2, :new_column2
      ...
    end
  end
end

Ensuite, db:migratecomme d'habitude ou comme vous allez pour vos affaires.


Pour Rails 4:

Lors de la création d'un Migrationpour renommer une colonne, Rails 4 génère une changeméthode au lieu de upet downcomme mentionné dans la section ci-dessus. La changeméthode générée est:

$ > rails g migration ChangeColumnName

qui va créer un fichier de migration similaire à:

class ChangeColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
nowk
la source
24
self.down devrait toujours être l'opposé de self.up, donc "si vous avez besoin ou faites autre chose ou ne faites rien" n'est pas vraiment recommandé. Faites juste: rename_column: table_name,: new_column,: old_column
Luke Griffiths
3
Bien qu'il soit normal de revenir sur ce que vous avez fait, self.upje ne dirais pas self.down"devrait toujours être opposé". En dépend du contexte de votre migration. Mettre simplement le «contraire» pourrait ne pas être la «bonne» migration vers le bas.
nowk
23
Dans Rails 3.1, vous pouvez remplacer def self.upet def self.downavec def changeet il saura comment revenir en arrière.
Turadg
2
Turadg - * il saura comment revenir en arrière la plupart du temps. Je trouve la changeméthode n'est pas une preuve complète, ont donc tendance à utiliser upet les downméthodes pour les migrations complexes.
JellyFishBoy
6
Le renommage supprime-t-il l'index?
Sung Cho
68

À mon avis, dans ce cas, il est préférable d'utiliser rake db:rollback, puis de modifier votre migration et d'exécuter à nouveau rake db:migrate.

Cependant, si vous avez des données dans la colonne que vous ne voulez pas perdre, utilisez-les rename_column.

elf.xf
la source
34
Même sur une "équipe d'un", si vous avez plusieurs instances de votre application en cours d'exécution, par exemple dans des environnements différents ou sur plusieurs ordinateurs, etc., la gestion des migrations modifiées est une difficulté majeure. Je modifie une migration uniquement si je viens de la créer et que je me suis rendu compte qu'elle était incorrecte et que je ne l'ai pas encore exécutée littéralement ailleurs.
Yetanotherjosh
1
J'ai dû redémarrer le serveur après cela.
Muhammad Hewedy
7
Cette technique ne doit être utilisée que dans une situation où vos modifications n'ont pas encore été fusionnées avec votre branche de production et où d'autres ne dépendent pas de la persistance des données. Dans la plupart des circonstances de production, ce n'est PAS la méthode préférée.
Collin Graves
4
ne fais jamais ce genre de choses.
new2cpp
4
J'aime dire à mon équipe: "Les migrations sont gratuites" était revenu en arrière et avait modifié une migration que j'avais déjà exécutée. Ne modifiez donc pas une migration existante, utilisez-en une nouvelle pour modifier le schéma, car ... ... 'Les migrations sont gratuites!' (ce n'est pas strictement vrai, mais cela fait le point)
TerryS
31

Si la colonne est déjà remplie de données et est en production, je recommanderais une approche étape par étape, afin d'éviter les temps d'arrêt en production en attendant les migrations.

Je créerais d'abord une migration de base de données pour ajouter des colonnes avec le ou les nouveaux noms et les remplir avec les valeurs de l'ancien nom de colonne.

class AddCorrectColumnNames < ActiveRecord::Migration
  def up
    add_column :table, :correct_name_column_one, :string
    add_column :table, :correct_name_column_two, :string

    puts 'Updating correctly named columns'
    execute "UPDATE table_name SET correct_name_column_one = old_name_column_one, correct_name_column_two = old_name_column_two"
    end
  end

  def down
    remove_column :table, :correct_name_column_one
    remove_column :table, :correct_name_column_two
  end
end

Ensuite, j'engagerais juste ce changement et le mettrais en production.

git commit -m 'adding columns with correct name'

Ensuite, une fois le commit mis en production, je courais.

Production $ bundle exec rake db:migrate

Ensuite, je mettrais à jour toutes les vues / contrôleurs qui faisaient référence à l'ancien nom de colonne au nouveau nom de colonne. Parcourez ma suite de tests et validez uniquement ces modifications. (Après vous être assuré qu'il fonctionnait localement et avoir réussi tous les tests en premier!)

git commit -m 'using correct column name instead of old stinky bad column name'

Ensuite, je pousserais cet engagement à la production.

À ce stade, vous pouvez supprimer la colonne d'origine sans vous soucier de tout type de temps d'arrêt associé à la migration elle-même.

class RemoveBadColumnNames < ActiveRecord::Migration
  def up
    remove_column :table, :old_name_column_one
    remove_column :table, :old_name_column_two
  end

  def down
    add_column :table, :old_name_column_one, :string
    add_column :table, :old_name_column_two, :string
  end
end

Poussez ensuite cette dernière migration vers la production et exécutez-la bundle exec rake db:migrateen arrière-plan.

Je me rends compte que c'est un peu plus impliqué dans un processus, mais je préfère le faire plutôt que d'avoir des problèmes avec ma migration de production.

Paul Pettengill
la source
2
J'aime la pensée derrière cela, et je voudrais attribuer +1 à votre répétition, mais cette mise à jour des données prendrait beaucoup de temps à exécuter car elle passe par des rails et fait une ligne à la fois. La migration s'exécuterait beaucoup plus rapidement avec des instructions SQL brutes pour mettre à jour les colonnes correctement nommées. Par exemple, dans le premier script de migration db, après avoir ajouté les noms de colonne en double, execute "Update table_name set correct_name_column_one = old_name_column_one"
Gui Weinmann
1
@ mr.ruh.roh ^ Tout à fait d'accord, aurait dû écrire cela en premier lieu. J'ai édité pour refléter une seule instruction sql efficace. Merci pour le contrôle de santé mentale.
Paul Pettengill
2
Que se passe-t-il avec les entrées entre le déplacement vers la nouvelle table et la mise à jour du code pour utiliser la nouvelle table? Ne pourriez-vous pas avoir de données potentiellement non migrées?
Stefan Dorunga du
1
bien qu'il s'agisse d'une réponse «sûre», je pense qu'elle est incomplète. Beaucoup de gens ici disent de ne pas faire ça - pourquoi? persistance des données. Et c'est valable. La façon la moins pénible d'atteindre l'objectif est probablement de créer les nouveaux champs, de les remplir avec les données des anciennes colonnes, d'ajuster les contrôleurs. Si vous souhaitez supprimer les anciennes colonnes, vous devrez certainement modifier les vues. Le coût de leur conservation est un espace supplémentaire de base de données et des efforts en double dans le contrôleur. Les compromis sont donc clairs.
Jerome
18

Exécutez la commande ci-dessous pour créer un fichier de migration:

rails g migration ChangeHasedPasswordToHashedPassword

Ensuite, dans le fichier généré dans le db/migratedossier, écrivez rename_columncomme ci-dessous:

class ChangeOldCoulmnToNewColumn < ActiveRecord::Migration
  def change
     rename_column :table_name, :hased_password, :hashed_password
  end
end
Shoaib Malik
la source
14

Depuis l'API:

rename_column(table_name, column_name, new_column_name)

Il renomme une colonne mais conserve le type et le contenu reste le même.

super_p
la source
12

Certaines versions de Ruby on Rails prennent en charge la méthode de montée / descente vers la migration et si vous avez une méthode de montée / descente dans votre migration, alors:

def up
    rename_column :table_name, :column_old_name, :column_new_name
end

def down
    rename_column :table_name, :column_new_name, :column_old_name
end

Si vous avez la changeméthode dans votre migration, alors:

def change
    rename_column :table_name, :column_old_name, :column_new_name
end

Pour plus d'informations, vous pouvez déplacer: Ruby on Rails - Migrations ou Migrations d'enregistrements actifs .

uma
la source
11

Si votre code n'est pas partagé avec un autre, la meilleure option est de le faire, rake db:rollback puis de modifier le nom de votre colonne dans la migration et rake db:migrate. C'est ça

Et vous pouvez écrire une autre migration pour renommer la colonne

 def change
    rename_column :table_name, :old_name, :new_name
  end

C'est ça.

sunil
la source
rake db:rollbackest une excellente suggestion. Mais comme vous l'avez dit, seulement si la migration n'a pas encore été repoussée.
danielricecodes
9

Comme alternative, si vous n'êtes pas marié avec l'idée de migrations, il existe un joyau convaincant pour ActiveRecord qui gérera automatiquement les changements de nom pour vous, le style Datamapper. Tout ce que vous faites est de changer le nom de la colonne dans votre modèle (et assurez-vous de mettre Model.auto_upgrade! Au bas de votre model.rb) et de l'alto! La base de données est mise à jour à la volée.

https://github.com/DAddYE/mini_record

Remarque: Vous devrez nuke db / schema.rb pour éviter les conflits

Toujours en phase bêta et évidemment pas pour tout le monde mais toujours un choix convaincant (je l'utilise actuellement dans deux applications de production non triviales sans aucun problème)

Steven Garcia
la source
8

Si vous devez changer de nom de colonne, vous devrez créer un espace réservé pour éviter une erreur de nom de colonne en double . Voici un exemple:

class SwitchColumns < ActiveRecord::Migration
  def change
    rename_column :column_name, :x, :holder
    rename_column :column_name, :y, :x
    rename_column :column_name, :holder, :y
  end
end
Abram
la source
7

Si les données actuelles ne sont pas importantes pour vous, vous pouvez simplement supprimer votre migration d'origine en utilisant:

rake db:migrate:down VERSION='YOUR MIGRATION FILE VERSION HERE'

Sans les guillemets, apportez des modifications à la migration d'origine et relancez la migration vers le haut en:

rake db:migrate
dirtydexter
la source
6

Créez simplement une nouvelle migration, et dans un bloc, utilisez rename_columncomme ci-dessous.

rename_column :your_table_name, :hased_password, :hashed_password
Jon Snow
la source
6

Pour Ruby on Rails 4:

def change
    rename_column :table_name, :column_name_old, :column_name_new
end
Hardik Hardiya
la source
5

Manuellement, nous pouvons utiliser la méthode ci-dessous:

Nous pouvons modifier la migration manuellement comme:

  • Ouvert app/db/migrate/xxxxxxxxx_migration_file.rb

  • Mettre hased_passwordà jour vershashed_password

  • Exécutez la commande ci-dessous

    $> rake db:migrate:down VERSION=xxxxxxxxx

Ensuite, il supprimera votre migration:

$> rake db:migrate:up VERSION=xxxxxxxxx

Il ajoutera votre migration avec la modification mise à jour.

Sumit Munot
la source
cela ne sera pas sûr car vous risquez de perdre des données - si la colonne est déjà en ligne. mais peut faire pour une nouvelle colonne et / ou table.
Tejas Patel
5

Générez le fichier de migration:

rails g migration FixName

# Crée db / migrate / xxxxxxxxxx.rb

Modifiez la migration pour faire votre volonté.

class FixName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
vipin
la source
5

Courez rails g migration ChangesNameInUsers(ou ce que vous voudriez lui donner)

Ouvrez le fichier de migration qui vient d'être généré et ajoutez cette ligne dans la méthode (entre def changeet end):

rename_column :table_name, :the_name_you_want_to_change, :the_new_name

Enregistrez le fichier et exécutez-le rake db:migratedans la console

Vérifiez votre schema.dbafin de voir si le nom a réellement changé dans la base de données!

J'espère que cela t'aides :)

Maddie
la source
5

Faisons un baiser . Il suffit de trois étapes simples. Les travaux suivants pour Rails 5.2 .

1 . Créer une migration

  • rails g migration RenameNameToFullNameInStudents

  • rails g RenameOldFieldToNewFieldInTableName- de cette façon, il est parfaitement clair pour les responsables de la base de code plus tard. (utilisez un pluriel pour le nom de la table).

2. Modifiez la migration

# I prefer to explicitly write thede haut en andbasmethods.

# ./db/migrate/20190114045137_rename_name_to_full_name_in_students.rb

class RenameNameToFullNameInStudents < ActiveRecord::Migration[5.2]
  def up
    # rename_column :table_name, :old_column, :new_column
    rename_column :students, :name, :full_name
  end

  def down
            # Note that the columns are reversed
    rename_column :students, :full_name, :name
  end
end

3. Exécutez vos migrations

rake db:migrate

Et c'est parti pour les courses!

BKSpurgeon
la source
4
$:  rails g migration RenameHashedPasswordColumn
invoke  active_record
      create    db/migrate/20160323054656_rename_hashed_password_column.rb

Ouvrez ce fichier de migration et modifiez ce fichier comme ci-dessous (entrez votre original table_name)

class  RenameHashedPasswordColumn < ActiveRecord::Migration
  def change
    rename_column :table_name, :hased_password, :hashed_password
  end
end
Prabhakar Undurthi
la source
4
 def change
    rename_column :table_name, :old_column_name, :new_column_name
  end
Apoorv
la source
3

Générez une migration Ruby on Rails :

$:> rails g migration Fixcolumnname

Insérez du code dans le fichier de migration (XXXXXfixcolumnname.rb) :

class Fixcolumnname < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
vipin
la source
2

Ouvrez votre console Ruby on Rails et entrez:

ActiveRecord::Migration.rename_column :tablename, :old_column, :new_column
rinold simon
la source
2

Vous avez deux façons de procéder:

  1. Dans ce type, il exécute automatiquement le code inverse de celui-ci, lors de la restauration.

    def change
      rename_column :table_name, :old_column_name, :new_column_name
    end
  2. Pour ce type, il exécute la méthode up quand rake db:migrateet exécute la méthode down lorsque rake db:rollback:

    def self.up
      rename_column :table_name, :old_column_name, :new_column_name
    end
    
    def self.down
      rename_column :table_name,:new_column_name,:old_column_name
    end
Sarwan Kumar
la source
2

Je suis sur les rails 5.2 et j'essaie de renommer une colonne sur un utilisateur de devise.

le rename_columnbit a fonctionné pour moi, mais le singulier a :table_namelancé une erreur "Table utilisateur non trouvée". Le pluriel a fonctionné pour moi.

rails g RenameAgentinUser

Ensuite, changez le fichier de migration en ceci:

rename_column :users, :agent?, :agent

Où: agent? est l'ancien nom de la colonne.

tombeau
la source
0

Update - Un proche cousin de create_table est change_table, utilisé pour changer les tables existantes. Il est utilisé de manière similaire à create_table mais l'objet cédé au bloc connaît plus de trucs. Par exemple:

class ChangeBadColumnNames < ActiveRecord::Migration
  def change
    change_table :your_table_name do |t|
      t.rename :old_column_name, :new_column_name
    end
  end
end

Cette façon est plus efficace si nous le faisons avec d'autres méthodes de modification telles que: supprimer / ajouter un index / supprimer un index / ajouter une colonne, par exemple, nous pouvons faire plus comme:

# Rename
t.rename :old_column_name, :new_column_name
# Add column
t.string :new_column
# Remove column
t.remove :removing_column
# Index column
t.index :indexing_column
#...
Hieu Pham
la source
0

Générez simplement la migration à l'aide de la commande

rails g migration rename_hased_password

Après cela, modifiez la migration, ajoutez la ligne suivante dans la méthode de changement

rename_column :table, :hased_password, :hashed_password

Cela devrait faire l'affaire.

Ratnam Yadav
la source
0

Modifications de la migration de Rails 5

par exemple:

rails g model Student nom_étudiant: string age: integer

si vous voulez changer la colonne nom_étudiant en nom

Remarque: - si vous n'exécutez pas rails db: migrez

Vous pouvez faire les étapes suivantes

rails modèle d Etudiant Student_name: string age: integer

Cela supprimera le fichier de migration généré, vous pouvez maintenant corriger le nom de votre colonne

rails g modèle Nom de l'élève: âge de la chaîne: entier

Si vous avez migré (rails db: migrate), les options suivantes pour modifier le nom de la colonne

migration des rails g RemoveStudentNameFromStudent nom_étudiant: chaîne

rails g migration AddNameToStudent nom: chaîne

prasanthrubyist
la source
Cela ne devrait-il pas être: rails g migration RemoveStudentNameFromStudentS student_name:string(les élèves sont pluriels)?
BKSpurgeon
C'est aussi dangereux: la colonne n'est pas renommée, mais entièrement supprimée puis lue à nouveau. Qu'adviendra-t-il des données? Ce n'est peut-être pas ce que l'utilisateur voudra.
BKSpurgeon