2012-01-27 13 views
59

Sono in procinto di aggiungere Devise a un'app di Rails esistente, con una tabella Utenti già definita. Il generatore devise spinto fuori la seguente migrazione:Qual è la sintassi corretta per remove_index in una migrazione di Rails 3.1.0?

class AddDeviseToUsers < ActiveRecord::Migration 
    def self.up 
    change_table(:users) do |t| 

    ## Database authenticatable 
    t.string :email,    :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 

    blah blah blah.... 

    end 

    add_index :users, :email,    :unique => true 
    add_index :users, :reset_password_token, :unique => true 
end 

la migrazione verso il basso non è generato, e sto avendo un mucchio di tempo rimuovere tali indici. Vedo diverse notazioni suggerite nella documentazione e diversi suggerimenti online, ma nessuno di loro sembra funzionare per me. Per esempio ...

def self.down 
    change_table(:users) do |t| 
    t.remove :email 
    t.remove :encrypted_password 

    t.remove :reset_password_token 

    blah blah blah... 
    end 

    remove_index :users, :email 
    remove_index :users, :reset_password_token 
end 

risultati in ...

An error has occurred, this and all later migrations canceled: 

Index name 'index_users_on_email' on table 'users' does not exist 

che è strano, perché se controllo il database, abbastanza sicuro, 'index_users_on_email' è proprio lì ...

che ho provato altre varianti, tra cui

remove_index :users, :column => :email 

remove_index :users, 'email' 

o:

change_table(:users) do |t| 
    t.remove_index :email 
end 

... ma nessun dado. Sto usando Rails 3.1.0, Ruby 1.9.2, rake 0.9.2.2, con Postgres.

Il comando che mi sta deludendo è:

bundle exec rake db:rollback STEP=1 

dopo applicare con successo la migrazione in su. Qualche consiglio?

+0

Ricordarsi inoltre di rimuovere prima l'indice e quindi rimuovere la colonna, i codici non funziona e non riuscirà anche se si utilizza una sintassi corretta. –

risposta

41

A seconda del tipo di database, non è necessario preoccuparsi di rimuovere gli indici nel metodo self.down poiché l'indice verrà automaticamente rimosso dal database quando si rilascia la colonna.

È inoltre possibile utilizzare questa sintassi nel metodo self.down:

def self.down 
    remove_column :users, :email 
    remove_column :users, :encrypted_password 
    remove_column :users, :reset_password_token 
end 
+8

In base alla risposta a questa domanda, gli indici non verranno eliminati quando si rilascia la colonna: http://stackoverflow.com/questions/7204476/will-removing-a-column-with-a-rails-migration-remove- gli indici associati allo – Solomon

+0

^dipende dal tipo di database – iwasrobbed

+0

Per ulteriore risposta di @iwasrobbed, prestare attenzione a questo approccio. Se hai un indice composito e rimuovi solo una delle colonne su MySQL, lascerà comunque l'indice. Basterà riferirsi alle colonne rimanenti. La risposta sotto è un approccio molto più sicuro per rimuovere esplicitamente l'indice. – gordysc

148

Per la cronaca, il modo per rimuovere un indice in base al nome è

remove_index(:table_name, :name => 'index_name') 

Quindi nel tuo caso

remove_index(:users, :name => 'index_users_on_email') 
+6

Per copia-paster con sintassi più recente: 'remove_index: users, name: 'index_users_on_email'' – Chambeur

54

È inoltre possibile rimuovere l'indice specificando le colonne, che dal mio punto di vista è meno err o incline di scrivere il nome

remove_index :actions, :column => [:user_id, :action_name] 
+8

Per la domanda questo sarebbe' remove_index: users, column:: email'. – Will

5

Mi piacerebbe espandere la risposta di @ iWasRobbed. Se si ha indice solo su una singola colonna, preoccuparsi di remove_index non ha senso poiché (solo una supposizione!) Il DB dovrebbe essere abbastanza intelligente da pulire le risorse utilizzate da tale indice. Ma nel caso in cui si abbia più colonne indice rimuovendo la colonna si ridurrà l'indice alle colonne ancora esistenti, che è una cosa assolutamente sensata da fare, ma una specie di show in cui si potrebbe voler usare esplicitamente lo remove_index.

Proprio per l'illustrazione - la migrazione di sotto ha quel difetto che dopo essere stato applicato su e giù lascerà l'indice univoco su email (cioè la parte down non sta facendo il suo lavoro correttamente)

class AddIndexes < ActiveRecord::Migration 
    def up 
    add_column :users, :action_name, :string 
    add_index :users, [:email, :action_name], unique: true 
    end 

    def down 
    remove_column :users, :action_name 
    end 
end 

Modifica della down blocco per

def down 
    remove_index :users, [:email, :action_name] 
    remove_column :users, :action_name 
    end 

risolverà quel difetto e consentire la migrazione di tornare correttamente DB allo stato precedente con rake db:rollback

0

Per modificare un tavolo e/o le sue tabelle utilizzare #change_table all'interno dell'azione #change di una migrazione. Allora si sarà in grado di creare la rimozione indice reversibile come segue:

def change 
    change_table :users do |t| 
     t.index :email, :unique => true 
     t.index :reset_password_token, :unique => true 
    end 
end 

Quando si deve eliminare una tabella con il suo indice, naturalmente, con azione reversibile è possibile utilizzare #drop_table metodo per SchemaStatements con il metodo #index di Table classe per ConnectionAdapter :

def change 
    drop_table :users do |t| 
     t.index :email, :unique => true 
     t.index :reset_password_token, :unique => true 
    end 
end 

nel caso in cui avete bisogno esattamente la #up/down accoppiamento in una migrazione. Utilizzare solo un metodo #change_table con #remove_index metodo Table classe per ConnectionAdapter:

def up 
    change_table :users do |t| 
     t.index :email, :unique => true 
     t.index :reset_password_token, :unique => true 
    end 
end 

def down 
    change_table :users do |t| 
     t.remove_index :email, :unique => true 
     t.remove_index :reset_password_token, :unique => true 
    end 
end 

Tutti i metodi sono disponibili in versione di Rails2.1.0 o di quelle precedenti.

0

Qui è la mia piena corsa di questo (in Rails 5):

ho team_id come un indice in tabella fornitori. Non ho più bisogno di questa relazione. Sbarazzarsi di. Ha fatto quanto segue:

1) creare la migrazione.

$ rails generate migration RemoveTeam_idFromVendor team_id:integer 

2) Esecuzione della migrazione, darmi questo errore. E questo è perché la tabella venditore ha righe i cui riferimenti chiave estera il valore della chiave primaria della tabella squadra

== 20170727202815 RemoveTeamIdFromVendor: migrating =========================== 
-- remove_column(:vendors, :team_id, :integer) 
rake aborted! 
StandardError: An error has occurred, this and all later migrations canceled: 

SQLite3::ConstraintException: FOREIGN KEY constraint failed: DROP TABLE "vendors" 

3) Per risolvere questo e ottenere la migrazione in esecuzione, ho fatto la seguente (Nota: io sono in dev) :

$ rake db:drop 


Dropped database 'db/development.sqlite3' 
Dropped database 'db/test.sqlite3' 


$ rake db:create 
Created database 'db/development.sqlite3' 
Created database 'db/test.sqlite3' 

$ rake db:migrate 
~ 
~ 
~ 

== 20170727202815 RemoveTeamIdFromVendor: migrating =========================== 
-- remove_column(:vendors, :team_id, :integer) 
    -> 0.0185s 
== 20170727202815 RemoveTeamIdFromVendor: migrated (0.0185s) ================== 
Problemi correlati