2010-06-19 5 views
20

Sto cercando di rastrellare il db: migrazioni nella mia istanza di heorku e ottengo un errore. Le FAQ descrivevano il mio errore come riportato di seguito:Come cambio il tipo di colonna in Heroku?

Cannot change column type

Example: PGError: ERROR: column “verified_at” cannot be cast to type “date”

Cause: PostgreSQL doesn’t know how to cast all the rows in that table to the specified type. Most likely it means you have an integer or a string in that column.

Solution: Inspect your records and make sure they can be converted to the new type. Sometimes it’s easier to just avoid using change_column, renaming/creating a new column instead.

Come modificare questa migrazione ora. Questo è il problema che ho. Per la mia tabella Contatti, ho creato il seguente:

t.string :date_entered 

In una migrazione tardi, faccio la seguente:

change_column :contacts, :date_entered, :date 

Questo change_column sembra essere il problema.

Devo ... modificare manualmente la migrazione? C'è un modo per pulire i dati nei miei tavoli (non sapevo che Heroku avrebbe riconosciuto i dati nella tabella perché sto facendo un rake).

Ovviamente ho bisogno di cambiare questo valore e viene utilizzato in tutta la mia applicazione. Grazie.

Questo è quello che sto provando ... pensieri?

def self.up 
    #change_column :contacts, :date_entered, :date 
    #this fails in postgres, so trying the same outcome 

    rename_column :contacts, :date_entered, :date_entered_old 
    add_column :contacts, :date_entered, :date 
    remove_column :contacts, :date_entered_old 
end 

def self.down 
    add_column :contacts, :date_entered_old 
    remove_column :contacts, :date_entered 
    rename_column :contacts, :date_entered_old, :date_entered 
end 

risposta

39

procedere come segue:

  1. rinominare la colonna A
  2. creare la nuova colonna B come data
  3. spostare i dati da A a B
  4. rimuovere un

In altre parole

def self.up 
    rename_column :contacts, :date_entered, :date_entered_string 
    add_column :contacts, :date_entered, :date 

    Contact.reset_column_information 
    Contact.find_each { |c| c.update_attribute(:date_entered, c.date_entered_string) } 
    remove_column :contacts, :date_entered_string 
end 
+0

+1 per #reset_column_information, che non avevo mai visto prima. Sembra che sarebbe utile in quei tempi molto rari in cui è necessario. – jdl

+0

idem re: reset. – Angela

+1

Ancora funziona oltre due anni dopo! –

1

Questa è una versione modificata e testata della soluzione di Simone Carletti

class ModifyContacts < ActiveRecord::Migration 
    def self.up 
    rename_column :contacts, :date_entered, :date_entered_string 
    add_column :contacts, :date_entered, :date 

    Contact.reset_column_information 
    Contact.find(:all).each { |contact| contact.update_attribute(:date_entered, contact.date_entered_string) } 
    remove_column :contacts, :date_entered_string 
    end 
end 
+1

Si vuole che 'find_each' sia. La tua versione leggerà l'intera tabella in memoria, mentre find_each otterrà un certo numero di righe alla volta. – clacke