Rails: Ajout d'un index après l'ajout d'une colonne

119

Supposons que j'ai créé une table tabledans une application Rails. Quelque temps plus tard, j'ajoute une colonne en cours d'exécution:

rails generate migration AddUser_idColumnToTable user_id:string. 

Ensuite, je me rends compte que je dois ajouter user_idcomme index. Je connais la add_indexméthode, mais où doit-on appeler cette méthode? Suis-je censé lancer une migration (si oui, laquelle?), Puis ajouter manuellement cette méthode?

user1611830
la source

Réponses:

235

Vous pouvez exécuter une autre migration, uniquement pour l'index:

class AddIndexToTable < ActiveRecord::Migration
  def change
    add_index :table, :user_id
  end
end
Jaap Haagmans
la source
4
Je lance donc simplement dans ma console: les rails génèrent la migration AddIndexToTable?
user1611830
3
Oui, vous pouvez le faire, mais vous devrez ensuite modifier cette migration pour refléter le code ci-dessus.
Jaap Haagmans
Est-ce que: table est censée être au pluriel?
tombeau le
1
@tomb J'ai utilisé l'exemple de la question d'origine. :tableest le nom réel de la table, donc dans le cas d'une userstable, vous feriez substituer :usersà :table.
Jaap Haagmans
65

Si vous avez besoin de créer un, user_idil serait raisonnable de supposer que vous référencez une table utilisateur. Dans ce cas, la migration sera:

rails generate migration AddUserRefToProducts user:references

Cette commande générera la migration suivante:

class AddUserRefToProducts < ActiveRecord::Migration
  def change
    add_reference :user, :product, index: true
  end
end

Après avoir exécuté à la rake db:migratefois une user_idcolonne et un index seront ajoutés à la productstable.

Dans le cas où vous avez juste besoin d'ajouter un index à une colonne existante, par exemple named'une usertable, la technique suivante peut être utile:

rails generate migration AddIndexToUsers name:string:index générera la migration suivante:

class AddIndexToUsers < ActiveRecord::Migration
  def change
    add_column :users, :name, :string
    add_index :users, :name
  end
end

Supprimez la add_columnligne et exécutez la migration.

Dans le cas décrit, vous auriez pu lancer une rails generate migration AddIndexIdToTable index_id:integer:indexcommande puis supprimer la add_columnligne de la migration générée. Mais je recommande plutôt d'annuler la migration initiale et d'ajouter une référence à la place:

rails generate migration RemoveUserIdFromProducts user_id:integer
rails generate migration AddUserRefToProducts user:references
Vadym Tyemirov
la source
Merci Vadym pour la réponse complète. Une dernière question: pourquoi recommanderiez-vous d'annuler la migration initiale? Y a-t-il un problème de performances lié à l'ajout d'un index ultérieurement?
Flavio Wuensche
2
Pour @fwuensche: il n'y a pas de pénalité de performance pour l'ajout d'un index plus tard. La logique du domaine sera cependant moins claire. Par exemple, si vous décidez de rompre / abstract / etc l'association plus tard, vous devrez gérer deux migrations distinctes, qui auraient vraiment dû être une seule ...
Vadym Tyemirov
6
AVERTISSEMENT: notez que index: true ne fonctionne que dans une migration create_table. La migration s'exécutera, mais aucun index ne sera créé. Voir makandracards.com/makandra/…
rmcsharry
9

Ajoutez dans la migration générée après avoir créé la colonne ce qui suit (exemple)

add_index :photographers, :email, :unique => true
rdeandrade
la source
vous voulez dire quelque chose comme ceci: def self.up add_column ... end add_index ...?
user1611830
6

Pour des références, vous pouvez appeler

rails generate migration AddUserIdColumnToTable user:references

Si, à l'avenir, vous devez ajouter un index général, vous pouvez lancer ce

rails g migration AddOrdinationNumberToTable ordination_number:integer:index

Générer du code:

class AddOrdinationNumberToTable < ActiveRecord::Migration
  def change
   add_column :tables, :ordination_number, :integer
   add_index :tables, :ordination_number, unique: true
  end
end
Mauro
la source
0

Vous pouvez l'utiliser, pensez simplement que Job est le nom du modèle auquel vous ajoutez l'index cader_id :

class AddCaderIdToJob < ActiveRecord::Migration[5.2]
  def change
    change_table :jobs do |t|
      t.integer :cader_id
      t.index :cader_id
    end
  end
end
vidur punj
la source