web-dev-qa-db-fra.com

Comment rédigez-vous une migration pour renommer un modèle ActiveRecord et sa table dans Rails?

Je ne parviens pas à nommer et je me rends compte qu'il existe un meilleur ensemble de noms pour mes modèles dans mon application Rails.
Existe-t-il un moyen d'utiliser une migration pour renommer un modèle et la table correspondante?

395
Readonly

Voici un exemple:

class RenameOldTableToNewTable < ActiveRecord::Migration
  def self.up
    rename_table :old_table_name, :new_table_name
  end

  def self.down
    rename_table :new_table_name, :old_table_name
  end
end

Je devais aller et renommer le fichier de déclaration de modèle manuellement.

Edit:

Dans Rails 3.1 & 4, ActiveRecord::Migration::CommandRecorder sait comment inverser les migrations rename_table. Vous pouvez ainsi:

class RenameOldTableToNewTable < ActiveRecord::Migration
  def change
    rename_table :old_table_name, :new_table_name
  end 
end

(Vous devez toujours passer et renommer manuellement vos fichiers.)

569
Readonly

Dans Rails 4 tout ce que je devais faire était de changer la définition

def change
  rename_table :old_table_name, :new_table_name
end

Et tous mes index ont été pris en charge pour moi. Je n'avais pas besoin de mettre à jour manuellement les index en supprimant les anciens et en ajoutant de nouveaux.

Et cela fonctionne en utilisant le changement pour monter ou descendre par rapport aux index également.

63
bfcoder

Les autres réponses et commentaires portaient sur le changement de nom de table, de fichier et sur votre code.

J'aimerais ajouter quelques mises en garde supplémentaires:

Prenons un exemple concret auquel je suis confronté aujourd’hui: renommer un modèle de "Merchant" à "Business".

  • N'oubliez pas de changer les noms des tables et modèles dépendants dans la même migration. J'ai modifié mes modèles Merchant et MerchantStat en Business et BusinessStat en même temps. Sinon, j'aurais dû faire beaucoup trop de choix lors de la recherche et du remplacement.
  • Pour tous les autres modèles dépendant de votre modèle via des clés étrangères, les noms de colonne des clés étrangères des autres tables seront dérivés du nom de votre modèle d'origine. Vous voudrez donc également faire des appels rename_column sur ces modèles dépendants. Par exemple, j'ai dû renommer la colonne 'merchant_id' en 'business_id' dans diverses tables de jointure (pour la relation has_and_belongs_to_many) et d'autres tables dépendantes (pour les relations normales has_one et has_many). Sinon, j'aurais fini avec des colonnes comme "business_stat.merchant_id" pointant vers "business.id". Voici une bonne réponse sur la manière de renommer les colonnes.
  • Lorsque vous faites un grepping, n'oubliez pas de rechercher les versions singulière, plurielle, majuscule, minuscule et même UPPERCASE (pouvant apparaître dans les commentaires) de vos chaînes.
  • Il est préférable de rechercher d'abord les versions au pluriel, puis au singulier. Ainsi, si vous avez un pluriel irrégulier - comme dans mon exemple marchands :: entreprises - vous pouvez corriger tous les pluriels irréguliers. Sinon, vous pouvez vous retrouver avec, par exemple, "businesss" (3 s) en tant qu'état intermédiaire, ce qui entraîne encore davantage de recherche-remplacement.
  • Ne remplacez pas aveuglément chaque occurrence. Si vos noms de modèle entrent en conflit avec des termes de programmation courants, avec des valeurs d'autres modèles ou avec du contenu textuel dans vos vues, vous risquez d'être trop impatient. Dans mon exemple, je souhaitais remplacer le nom de mon modèle par "Business", mais je le désignais toujours comme "marchand" dans le contenu de mon interface utilisateur. J'ai également eu un rôle de "marchand" pour mes utilisateurs dans CanCan - c'est la confusion entre le rôle de commerçant et le modèle de marchand qui m'a amené à renommer le modèle en premier lieu.
45
armchairdj

Vous devez également remplacer vos index:

class RenameOldTableToNewTable< ActiveRecord:Migration
  def self.up
    remove_index :old_table_name, :column_name
    rename_table :old_table_name, :new_table_name
    add_index :new_table_name, :column_name
  end 

  def self.down
    remove_index :new_table_name, :column_name
    rename_table :new_table_name, :old_table_name
    add_index :old_table_name, :column_name
  end
end

Et renommez vos fichiers, etc. manuellement, comme décrit dans les autres réponses.

Voir: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

Assurez-vous de pouvoir revenir en arrière et revenir en arrière après avoir écrit cette migration. Cela peut devenir délicat si vous vous trompez et que vous vous retrouvez avec une migration qui tente de réaliser quelque chose qui n'existe plus. Il est préférable de supprimer toute la base de données et de recommencer si vous ne pouvez pas revenir en arrière. Alors sachez que vous pourriez avoir besoin de sauvegarder quelque chose.

Également: recherchez schema_db pour tout nom de colonne pertinent dans les autres tables définies par has_ ​​ou apart_to ou quelque chose d'autre. Vous aurez probablement besoin de les éditer aussi.

Et enfin, le faire sans une suite de tests de régression serait fou.

23
Rimian