2010-06-19 6 views
20

J'essaie de ramener les migrations db: dans mon instance heorku et j'obtiens une erreur. La FAQ décrit mon erreur comme ci-dessous:Comment changer le type de colonne dans 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.

Comment puis-je modifier cette migration maintenant. C'est le problème que j'ai. Pour ma table Contacts, j'ai créé les éléments suivants:

t.string :date_entered 

Dans une migration plus tard, je fais ce qui suit:

change_column :contacts, :date_entered, :date 

Ce change_column semble être le problème.

Dois-je ... changer à la main cette migration? Y at-il un moyen de nettoyer les données dans mes tables (je ne savais pas que Heroku reconnaîtrait les données dans la table parce que je fais un rake).

Je dois évidemment changer cette valeur et elle est utilisée dans toute mon application. Merci.

C'est ce que j'essaie ... des pensées?

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 

Répondre

39

Effectuez les opérations suivantes:

  1. Renommez la colonne A
  2. créer la nouvelle colonne B que la date
  3. déplacer les données de A à B
  4. supprimer un

En d'autres termes

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 pour #reset_column_information, que je ne l'avais jamais vu auparavant. Cela semble être pratique dans les très rares moments où cela est nécessaire. – jdl

+0

idem re: réinitialiser. – Angela

+1

Fonctionne encore plus de deux ans plus tard! –

1

Ceci est une version modifiée et testée de la solution de 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

Vous voulez que 'find_each' cependant. Votre version lira toute la table en mémoire, alors que find_each aura un certain nombre de lignes à la fois. – clacke

Questions connexes