Ajout d'une colonne à une table existante dans une migration Rails

340

J'ai un modèle Utilisateurs qui a besoin d'une :emailcolonne (j'ai oublié d'ajouter cette colonne lors de l'échafaudage initial).

J'ai ouvert le fichier de migration et ajouté t.string :email, fait rake db:migrateet obtenu un fichier NoMethodError. J'ai ensuite ajouté la ligne

add_column :users, :email, :string

encore rake db:migrate, encore NoMethodError. Suis-je en train de manquer une étape ici?

Edit: voici le fichier de migration.

class CreateUsers < ActiveRecord::Migration  
  def self.up  
    add_column :users, :email, :string  
    create_table :users do |t|  
      t.string :username  
      t.string :email  
      t.string :crypted_password  
      t.string :password_salt  
      t.string :persistence_token  

      t.timestamps  
    end  
  end  

  def self.down  
    drop_table :users  
  end  
end
John
la source

Réponses:

574

Si vous avez déjà exécuté votre migration d'origine (avant de la modifier), vous devez générer une nouvelle migration ( rails generate migration add_email_to_users email:stringfera l'affaire). Il créera un fichier de migration contenant la ligne: add_column :users, email, string Ensuite, faites un rake db:migrateet il exécutera la nouvelle migration, créant la nouvelle colonne.

Si vous n'avez pas encore exécuté la migration d'origine, vous pouvez simplement la modifier, comme vous essayez de le faire. Votre code de migration est presque parfait: il vous suffit de supprimer add_columncomplètement la ligne (ce code essaie d'ajouter une colonne à une table, avant la création de la table, et votre code de création de table a déjà été mis à jour pour en inclure de t.string :emailtoute façon).

Dylan Markow
la source
6
Pour être clair, nous utilisons le pluriel? C'est donc add_email_to_userset NON add_email_to_user?
Purplejacket
9
Correct. Les noms de table dans Rails sont toujours pluriels (pour correspondre aux conventions DB).
camdez
2
Vous pouvez également utiliser rails db:migratepour la dernière étape.
Dylan Vander Berg
Est-il possible de créer une nouvelle colonne sur une position particulière dans une table. Par exemple, si je veux créer un nouveau champ "status" juste après le champ "email" existant?
neeraj
2
@neeraj vous avez probablement la réponse maintenant mais pour les autres demandeurs, oui vous pouvez comme par exemple t.string :column_x, limit: 10, after: :column_y(pour Rails 4 au moins)
244an
124

Utilisez cette commande sur la console des rails

rails generate migration add_fieldname_to_tablename fieldname:string

et

rake db:migrate

pour exécuter cette migration

vinodh
la source
57

Produit parfois rails generate migration add_email_to_users email:stringune migration comme celle-ci

class AddEmailToUsers < ActiveRecord::Migration[5.0]
  def change
  end
end

Dans ce cas, vous devez manuellement un add_columnpour change:

class AddEmailToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :email, :string
  end
end

Et puis exécutez rake db:migrate

Apoorv Agarwal
la source
1) Doit- rails generate migration add_email_to_users email:stringil être exécuté après bundle exec rails cou juste à l'intérieur du terminal? 2) Où est placé le fichier généré une fois que nous avons exécuté la requête?
sofs1
28

Vous pouvez aussi faire

rake db:rollback

si vous n'avez ajouté aucune donnée aux tables. Modifiez ensuite le fichier de migration en y ajoutant la colonne e-mail, puis appelez

rake db:migrate

Cela fonctionnera si vous avez installé des rails 3.1 dans votre système.

Une manière beaucoup plus simple de le faire est de changer le changement de fichier de migration tel quel. utilisation

$rake db:migrate:redo

Cela annulera la dernière migration et la migrera à nouveau.

Ninz
la source
21

Pour ajouter une colonne, je devais simplement suivre ces étapes:

  1. rails generate migration add_fieldname_to_tablename fieldname:string

    Alternative

    rails generate migration addFieldnameToTablename

    Une fois la migration générée, modifiez la migration et définissez tous les attributs que vous souhaitez ajouter à cette colonne.

    Remarque : Les noms de table dans Rails sont toujours pluriels (pour correspondre aux conventions DB). Exemple utilisant l'une des étapes mentionnées précédemment-

    rails generate migration addEmailToUsers

  2. rake db:migrate

Ou

  1. Vous pouvez modifier le schéma depuis db/schema.rb, ajoutez les colonnes de votre choix dans la requête SQL.
  2. Exécutez cette commande: rake db:schema:load

    Avertissement / Remarque

    Gardez à l'esprit que l'exécution rake db:schema:loadefface automatiquement toutes les données de vos tables.

Pratik Naik
la source
Je l'ai fait, mais il n'a pas refait l'échafaudage et ajouté la nouvelle colonne. Comment puis-je faire cela "automagiquement"?
John Wooten
@John Wooten, vous voudrez peut-être supprimer l'échafaudage et le parcourir à nouveau. Supprimez également les migrations correspondantes.
Afolabi Olaoluwa Akinwumi
pour ajouter une note: changer le schéma sans changer la migration peut créer des problèmes avec d'autres développeurs qui maintiennent l'application.
BKSpurgeon
3

Lorsque j'ai fait cela, plutôt que de tripoter la migration d'origine, j'en crée une nouvelle avec juste la colonne d'ajout dans la section vers le haut et une colonne de suppression dans la section vers le bas.

Vous pouvez changer l'original et le réexécuter si vous migrez entre les deux, mais dans ce cas, je pense que cela a fait une migration qui ne fonctionnera pas correctement.

Tel que publié actuellement, vous ajoutez la colonne, puis créez le tableau.

Si vous changez l'ordre, cela pourrait fonctionner. Ou, lorsque vous modifiez une migration existante, ajoutez-la simplement à la table de création au lieu de faire une colonne d'ajout distincte.

Don Roby
la source
1

Vous pouvez également forcer à placer des colonnes dans la table à l'aide de force: true, si votre table existe déjà.

exemple :

ActiveRecord::Schema.define(version: 20080906171750) do
  create_table "authors", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end
end
Aravin
la source
1

Vous pouvez également utiliser la méthode spéciale change_table dans la migration pour ajouter de nouvelles colonnes:

change_table(:users) do |t|
  t.column :email, :string
end
ruslanimos
la source
0

Vous pouvez annuler la dernière migration en

rake db:rollback STEP=1

ou annuler cette migration spécifique par

rake db:migrate:down VERSION=<YYYYMMDDHHMMSS>

et modifiez le fichier, puis réexécutez rake db:mirgate.

fangxing
la source
0

Vous pouvez également le faire .. migration des rails g add_column_to_users email: string

puis râteau db: migrate ajouter également: attribut email dans votre contrôleur d'utilisateur;

pour plus de détails, consultez http://guides.rubyonrails.org/active_record_migrations.html

aaquib
la source
0

Vous pouvez également ajouter une colonne à une position spécifique en utilisant avant la colonne ou après la colonne comme:

rails generate migration add_dob_to_customer dob:date

Le fichier de migration générera le code suivant sauf après:: email. vous devez ajouter après:: email ou avant:: email

class AddDobToCustomer < ActiveRecord::Migration[5.2]
  def change
    add_column :customers, :dob, :date, after: :email
  end
end
Khabir
la source