2012-03-02 5 views
19

J'ai un modèle avec une colonne de type integer que je veux convertir en type string. Maintenant, je cherche la meilleure façon de changer le type de colonne sans perdre les données. Existe-t-il un moyen indolore d'accomplir ceci?Rails: changer le type de colonne, mais conserver les données

+1

Est-ce une seule fois, ou voulez-vous que cela fonctionne à plusieurs reprises, par exemple, dans une migration? –

Répondre

33

Une migration standard utilisant la méthode change_column convertira des entiers en chaînes sans aucune perte de données. rake db: rollback effectuera également la migration inverse sans erreur si nécessaire.

Voici la migration de test je confirmer ce comportement:

class ChangeAgeToString < ActiveRecord::Migration 
    def self.up 
    change_column :users, :age, :string 
    end 

    def self.down 
    change_column :users, :age, :integer 
    end 
end 
+0

Pour une raison qui ne fonctionne pas pour moi. J'utilise les rails 3.2.13 avec mysql 14.14 sur un Mac, et la migration ci-dessus change tous mes: valeurs entières à 0 – gardenofwine

+1

Je viens de re-testé avec les versions que vous avez mentionnées (Rails 3.2.13 et mysql Ver 14.14 Distrib 5.5.27, pour osx10.8 (i386) en utilisant readline 5.1). Tout a fonctionné comme prévu. Avant la migration (=> # ) après la migration (=> # ). Qu'avez-vous fait différemment gardenofwine? – Jon

+0

J'éprouve quelque chose de similaire à @gardenofwine mais en convertissant la colonne de 'time' en' datetime'. Si les données d'origine sont "09:30:30", après la migration, je reçois tous les zéros. J'utilise Rails 3.2.12 et la même version de mysql que @Jon. Une idée de comment cela peut arriver. – elhoyos

2

Si c'est un unique, vous pouvez simplement changer le type de colonne dans la base de données (puisqu'aucune information est perdue passer d'int à varchar)

Pour MySQL, cela ferait:

ALTER TABLE t1 MODIFY col1 VARCHAR(256) 

Si vous utilisez SQLite, vous n'aurez rien à faire.

+0

J'utilise postgresql dans le projet actuel et cela a fonctionné aussi! Merci pour votre réponse, j'ai mis le message suivant comme réponse acceptée simplement parce que je pense que la plupart des utilisateurs qui ont cette question pourraient avoir besoin d'une migration. – blissini

+0

Cool. Oui, la réponse de migration est la meilleure. J'étais en train de travailler sur une base de données MySql à l'époque, donc la réponse à la base de données me semblait d'abord! –

3

pour postgres dans la migration

change_column :table_name, :field,'boolean USING (CASE field WHEN \'your any string as true\' THEN \'t\'::boolean ELSE \'f\'::boolean END)' 

et à tout type valide similaire

1

Si vous utilisez Postgres, vous ne pouvez pas renvoyer implicitement une chaîne à un entier, donc la manière de rendre le changement réversible est:

class ChangeAgeToString < ActiveRecord::Migration 
    def self.up 
    change_column :users, :age, :string 
    end 

    def self.down 
    add_column :age_integer 
    User.connection.execute('UPDATE users SET age_integer = cast(age as int)') 
    remove_column :users, :age 
    rename_column :users, :age_integer, :age 
    end 
end 
0

pour postgresql, colonne table à langer datatype integer-string,
rails migration like this with up and down actions

class ChangeAgeToString < ActiveRecord::Migration 
    def self.up 
    change_column :users, :age, 'varchar USING CAST(age AS varchar)', null: false 
    end 

    def self.down 
    change_column :users, :age, 'integer USING CAST(age AS integer)', null: false, default: 0 
    end 
end 
Questions connexes