web-dev-qa-db-fra.com

Les rails créant une migration pour ajouter des colonnes à la table provoquent une erreur lors de l'exécution de rake db: migrate

J'ai créé un modèle appelé "utilisateurs" et j'ai créé une nouvelle migration pour ajouter des colonnes à la table des utilisateurs. Maintenant, quand je lance rake db: migrate, j'obtiens l'erreur ci-dessous, car il essaie de créer à nouveau la table users

$ rake db:migrate
==  DeviseCreateUsers: migrating ==============================================
-- create_table(:users)
rake aborted!
An error has occurred, all later migrations canceled:

Mysql::Error: Table 'users' already exists: CREATE TABLE `users`.....

Pourquoi essaie-t-il de créer à nouveau la table?

Voici la commande que j'ai utilisée pour créer la nouvelle migration

$ Rails generate migration AddDetailsToUsers home_phone:decimal cell_phone:decimal work_phone:decimal birthday:date home_address:text work_address:text position:string company:string

La nouvelle migration ressemble à ceci:

class AddDetailsToUsers < ActiveRecord::Migration
  def change
    add_column :users, :home_phone, :decimal
    add_column :users, :cell_phone, :decimal
    add_column :users, :work_phone, :decimal
    add_column :users, :birthday, :date
    add_column :users, :home_address, :text
    add_column :users, :work_address, :text
    add_column :users, :position, :string
    add_column :users, :company, :string
  end
end

MODIFIER

20120511224920_devise_create_users

class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table(:users) do |t|
      ## Database authenticatable
      t.string :email,              :null => false, :default => ""
      t.string :username,           :null => false, :default => ""
      t.string :encrypted_password, :null => false, :default => ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, :default => 0
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Encryptable
      # t.string :password_salt

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at

      ## Token authenticatable
      # t.string :authentication_token


      t.timestamps
    end

    add_index :users, :email,                :unique => true
    add_index :users, :reset_password_token, :unique => true
    # add_index :users, :confirmation_token,   :unique => true
    # add_index :users, :unlock_token,         :unique => true
    # add_index :users, :authentication_token, :unique => true
  end
end

20120619023856_add_name_to_users

class AddNameToUsers < ActiveRecord::Migration
  def change
    add_column :users, :first_name, :string
    add_column :users, :last_name, :string
  end
end

20121031174720_add_details_to_users.rb

class AddDetailsToUsers < ActiveRecord::Migration
  def change
    add_column :users, :home_phone, :decimal
    add_column :users, :cell_phone, :decimal
    add_column :users, :work_phone, :decimal
    add_column :users, :birthday, :date
    add_column :users, :home_address, :text
    add_column :users, :work_address, :text
    add_column :users, :position, :string
    add_column :users, :company, :string
  end
end
22
Catfish

Rails garde la trace des migrations dans la table "schema_migrations" de votre base de données. À moins d'une entrée pour "20120511224920", qui correspond à la migration de Devise, il tentera de l'exécuter à nouveau, ce qui semble déjà exister.

Vous pouvez l'ajouter manuellement à la table si c'est le cas.

11
omarvelous

L'erreur indique qu'il tente d'exécuter à nouveau la migration DeviseCreateUsers d'origine et ne peut pas le faire car la table users existe déjà.

Pour résoudre ce problème, vous pouvez exécuter la migration vers le bas pour DeviseCreateUsers, puis exécuter les migrations normalement. Vous pouvez le faire avec:

rake db:migrate:down VERSION=20121031XXXXXXXX
rake db:migrate

20121031XXXXXXXX correspond à l'horodatage du nom de la migration. En d'autres termes, vous aurez une migration nommée 20120410214815_devise_create_users.rb et vous copiez l'horodatage à partir du nom de fichier et le collez dans la commande. Voici le Guide Rails sur les migrations .

Edit: Ceci est noté dans les commentaires, mais juste un mot d'avertissement. L'exécution de la migration vers le bas pour une table perdra toutes les entrées de cette table. Je suppose que vous travaillez en mode développement, donc cela ne devrait pas poser de problème. Si vous êtes en production, vous devrez prendre des mesures supplémentaires pour sauvegarder les données de la table et les recharger après, sinon vous passerez une mauvaise journée (ou peut-être une semaine).

6
GorrillaMcD

Pouvez-vous essayer de créer une nouvelle base de données puis de la migrer à nouveau:

rake db:drop:all
rake db:create:all
rake db:migrate
5
Thanh

Donc, d'après ce que j'en ai tiré:

  • Vous avez déjà eu un modèle utilisateur
  • Vous avez une version de ceci en production
  • Vous avez exécuté un Rails par défaut générer: installer
  • Vous avez ensuite lancé Rails Gener, concevez un utilisateur

J'espère que:

  • Vous utilisez le contrôle de source
  • Vous vérifiez le code dans un lot

NOTE: Sinon, vous êtes sur le point de savoir pourquoi vous devez le faire.

Revenez à votre code avant de générer Devise

Espérons que vous pouvez simplement créer un nouveau bac à sable d'un point juste avant de générer Devise. Sinon, copiez votre répertoire de projet et faites-le à la main. La seule autre option est de modifier manuellement tous les fichiers générés par Devise.

Relancez votre génération Devise

  • joyau lu 'concevoir' à votre Gemfile
  • Les rails génèrent un montage: installer
  • Les rails génèrent un modèle

Assurez-vous que ce modèle n'existe pas! Si vous n'entrez pas dans le problème que vous rencontrez actuellement.

Migrer les utilisateurs actuels d'un modèle à l'autre

Si vous pouvez générer un script pour déplacer complètement les informations d'authentification de votre ancien modèle d'utilisateur vers le nouveau, c'est bon pour vous. Si vous utilisez un algorithme de hachage différent de Devise pour votre authentification actuelle, vous allez alors invalider tous leurs mots de passe et demander à vos utilisateurs de créer un nouveau mot de passe en utilisant un code de confirmation dans leur courrier électronique OR que vous pouvez migrer. utilisateurs lorsqu’ils se connectent. La première méthode est propre, complète et grossière. La seconde méthode est laide, incomplète et silencieuse. Choisissez votre méthode comme bon vous semble. 

Edit: Vous pourriez probablement trouver un moyen de personnaliser Devise pour utiliser votre algorithme à la place. Ce serait probablement encore mieux, mais un peu plus de travail et assez fragile.

Une autre chose est que votre modèle d'authentification ne doit pas être surchargé de données de compte. Vous devriez avoir un modèle qui gère uniquement l’authentification, qui a_un modèle de données de compte qui stocke tout ce que vous voudriez suivre sur les comptes.

2
Michael McGuire

utiliser des méthodes de haut en bas. Cela sera utile pour la restauration et l'exécution d'un fichier de migration spécifique.

S'il vous plaît suivez la syntaxe ..

  class AddDetailsToUsers < ActiveRecord::Migration
    def self.up
      add_column :users, :home_phone, :decimal
      add_column :users, :cell_phone, :decimal
      add_column :users, :work_phone, :decimal
      add_column :users, :birthday, :date
      add_column :users, :home_address, :text
      add_column :users, :work_address, :text
      add_column :users, :position, :string
      add_column :users, :company, :string
   end

   def self.down
      remove_column :users, :home_phone
      remove_column :users, :cell_phone
      remove_column :users, :work_phone
      remove_column :users, :birthday
      remove_column :users, :home_address
      remove_column :users, :work_address
      remove_column :users, :position
      remove_column :users, :company
   end
  end


    In this case please try to migrate using version number.

Comme rake db: migrate: down VERSION = numéro de version # numéro de version est la version que vous souhaitez migrer.

2
vijikumar

Recherchez certaines variables d'environnement susceptibles de fournir une valeur inattendue pour la version de votre migration. J'ai trouvé une vieille question sur Stack Overflow (et pardonnez-moi si c'est obsolète) où db:migrate détruisait la table, au lieu d'appliquer une nouvelle migration existante. 

Ils ont finalement découvert qu'une variable d'environnement provoquait l'exécution de db:migrate avec un paramètre de version de "0" fonctionnellement équivalent à rake db:migrate:down.

Est-il possible que votre situation soit due à une modification inattendue de la version afin d'inclure ou de faire correspondre la migration précédente DeviseCreateUsers?

1
lutze

Je suppose que vous avez parfois utilisé Rails generate devise user qui a généré DeviseCreateUsers. Si vous avez déjà créé un modèle d'utilisateur et une table d'utilisateurs, vous pouvez supprimer le fichier de migration généré de db/migrate.

1
Yanhao

Et si vous avez besoin de faire des migrations sales manuellement:

class A < ActiveRecord::Migration
  def up
    add_column :images, :name
  end
end

A.new.migrate(:up)
0
Dorian

juste essayer 

dans le premier fichier 

create_table(:users), :force => true do |t|

cela remplacera toute autre table

0

Selon ce que vous avez dit, vous avez utilisé cette commande pour créer une nouvelle migration.

$ Rails génère la migration AddDetailsToUsers home_phone: decimal cell_phone: decimal work_phone: decimal anniversaire: date home_address: text work_address: position text: string company: string

Je ne suis pas sûr que ce soit juste une faute de frappe, mais il devrait s'agir de "AddDetailsToUser" et non de "Utilisateurs". Il suffit de vérifier à nouveau et nous serons en mesure de vous aider. Ceci est pour le modèle généré. Lorsque vous mentionnez User, la base de données recherche des utilisateurs.

Ruby on Rails suit linguistic convention.nom_table est pluriel mais nom_module est singulier. Vous devez utiliser model_name dans la commande que vous avez utilisée.

Si vous voulez utiliser nom_table, utilisez ceci 

Rails g migration add_details_to_users home_phone: décimal ...... etc

0
Nikhil Nanjappa