Je suis déjà allé sur Google un peu et il semble qu'il n'y ait pas de réponse satisfaisante à mon problème.
J'ai une table avec une colonne de type chaîne. Je voudrais exécuter la migration suivante:
class ChangeColumnToBoolean < ActiveRecord::Migration
def up
change_column :users, :smoking, :boolean
end
end
Lorsque je lance ceci, j'obtiens l'erreur suivante
PG::Error: ERROR: column "smoking" cannot be cast automatically to type boolean
HINT: Specify a USING expression to perform the conversion.
: ALTER TABLE "users" ALTER COLUMN "smoking" TYPE boolean
Je sais que je peux effectuer cette migration en utilisant du SQL pur, mais ce serait quand même mieux si je pouvais le faire avec Rails. J'ai parcouru le code Rails et ne semble pas y avoir une telle possibilité, mais peut-être que quelqu'un connaît un moyen?
Je ne suis pas intéressé par: - SQL pur - supprimer la colonne - créer une autre colonne, convertir des données, supprimer l'original puis renommer
Depuis que j'utilise Postgres, je suis allé avec la solution SQL pour l'instant. Requête utilisée:
execute 'ALTER TABLE "users" ALTER COLUMN "smoking" TYPE boolean USING CASE WHEN "flatshare"=\'true\' THEN \'t\'::boolean ELSE \'f\'::boolean END'
Cela ne fonctionne que si l'on a un champ rempli de chaînes vraies/fausses (comme l'aide à la collecte de boutons radio par défaut avec le type booléen forcé)
Si vos chaînes dans la colonne smoking
sont déjà des valeurs booléennes valides, l'instruction suivante changera le type de colonne sans perdre de données:
change_column :users, :smoking, 'boolean USING CAST(smoking AS boolean)'
De même, vous pouvez utiliser cette instruction pour convertir des colonnes en entier:
change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'
J'utilise Postgres. Je ne sais pas si cette solution fonctionne pour d'autres bases de données.
Toutes les bases de données ne permettent pas de changer le type de colonne, l'approche généralement adoptée consiste à ajouter une nouvelle colonne du type souhaité, à apporter des données, à supprimer l'ancienne colonne et à renommer la nouvelle.
add_column :users, :smoking_tmp, :boolean
User.reset_column_information # make the new column available to model methods
User.all.each do |user|
user.smoking_tmp = user.smoking == 1 ? true : false # If smoking was an int, for example
user.save
end
# OR as an update all call, set a default of false on the new column then update all to true if appropriate.
User.where(:smoking => 1).update_all(:smoking_tmp = true)
remove_column :users, :smoking
rename_column :users, :smoking_tmp, :smoking
Donc bon pour booléen en postgres:
change_column :table_name, :field,'boolean USING (CASE field WHEN \'your any string as true\' THEN \'t\'::boolean ELSE \'f\'::boolean END)'
et vous pouvez ajouter des conditions WHEN
- THEN
supplémentaires dans votre expression
Pour les autres serveurs de base de données, l'expression sera construite sur la base de la syntaxe de votre serveur de base de données, mais le principe est le même. Seul algorithme de conversion manuelle, entièrement sans SQL il n'y en a malheureusement pas assez.
Way avec la syntaxe change_column :table, :filed, 'boolean USING CAST(field AS boolean)'
ne convient que si le contenu du champ quelque chose comme: true/false/null