ruby on rails - remove - Migraciones de carriles-change_column con conversión de tipo
rollback migration rails (4)
Ya google''d surgió un poco y parece que no hay una respuesta satisfactoria para mi problema.
Tengo una tabla con columna de tipo cadena. Me gustaría ejecutar la siguiente migración:
class ChangeColumnToBoolean < ActiveRecord::Migration
def up
change_column :users, :smoking, :boolean
end
end
Cuando ejecuto esto recibo un error de seguimiento
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
Sé que puedo realizar esta migración usando SQL puro, pero aún así sería mejor si pudiera hacerlo con Rails. Revisé el código de Rails y parece que no hay tal posibilidad, pero ¿alguien sabe cómo?
No estoy interesado en: - SQL puro - dejando caer la columna - creando otra columna, convirtiendo datos, soltando el original y luego cambiando el nombre
Así que correcto para booleano en postgres:
change_column :table_name, :field,''boolean USING (CASE field WHEN /'your any string as true/' THEN /'t/'::boolean ELSE /'f/'::boolean END)''
y puedes agregar algo más de WHEN
- THEN
en tu expresión
Para otros servidores de bases de datos, la expresión se construirá en base a la sintaxis para su servidor de base de datos, pero el principio es el mismo. Solo el algoritmo de conversión manual, completamente sin SQL, no es suficiente por desgracia.
Manera con la sintaxis change_column :table, :filed, ''boolean USING CAST(field AS boolean)''
solo es adecuado si el contenido del campo es algo así como: true / false / null
No todas las bases de datos permiten cambiar el tipo de columna, el enfoque generalmente adoptado es agregar una nueva columna del tipo deseado, traer todos los datos, eliminar la columna anterior y renombrar la nueva.
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
Si sus cadenas en smoking
columna de smoking
ya son valores booleanos válidos, la siguiente declaración cambiará el tipo de columna sin perder datos:
change_column :users, :smoking, ''boolean USING CAST(smoking AS boolean)''
Del mismo modo, puede usar esta instrucción para convertir columnas en números enteros:
change_column :table_name, :column_name, ''integer USING CAST(column_name AS integer)''
Estoy usando Postgres. No estoy seguro de si esta solución funciona para otras bases de datos.
Ya que estoy usando Postgres, fui con la solución SQL por ahora. Consulta utilizada:
execute ''ALTER TABLE "users" ALTER COLUMN "smoking" TYPE boolean USING CASE WHEN "flatshare"=/'true/' THEN /'t/'::boolean ELSE /'f/'::boolean END''
Funciona solo si uno tiene un campo lleno de cadenas verdaderas / falsas (como por ejemplo, el asistente de recolección de botones de radio predeterminado con el tipo de booleano forzado generaría)