Migraciones de rails-cambiar columna con conversión de tipo
Yo ya aroung Google un poco y parece que no hay respuesta satisfactoria para mi problema.
Tengo una tabla con columna de tipo string. Me gustaría ejecutar la siguiente migración:
class ChangeColumnToBoolean < ActiveRecord::Migration
def up
change_column :users, :smoking, :boolean
end
end
Cuando corro esto obtengo el siguiente error
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. Pasé por el código Rails y parece que no hay tal posibilidad, pero tal vez alguien sabe una manera?
No soy interesar: - SQL puro - dejar caer la columna - la creación de otra columna, la conversión de datos, dejar caer original y luego cambiar el nombre
4 answers
Si sus cadenas en la columna smoking
ya son valores booleanos válidos, la siguiente instrucción cambiará el tipo de columna sin perder datos:
change_column :users, :smoking, 'boolean USING CAST(smoking AS boolean)'
De manera similar, puede usar esta instrucción para convertir columnas en 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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-03 08:35:34
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 cualquier dato, eliminar la columna anterior y cambiar el nombre de 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-14 12:47:35
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 usted puede añadir un poco más WHEN
- THEN
condición en su expresión
Para otros servidores de base de datos, la expresión se construirá en base a la sintaxis de su servidor de base de datos, pero el principio es el mismo. Solo algoritmo de conversión manual, totalmente sin SQL no hay suficiente por desgracia.
Way with syntax change_column :table, :filed, 'boolean USING CAST(field AS boolean)'
es adecuado solo si el contenido del campo es algo como: true / false / null
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-03 15:05:23
Ya que estoy usando Postgres, me 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 true/false (como el ayudante de colección de botones de opción predeterminados con tipo booleano forzado generaría)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-12 21:34:59