Подтвердить что ты не робот

Переходы Rails - change_column с преобразованием типов

Я уже немного разобрался и не вижу удовлетворительного ответа на мою проблему.

У меня есть таблица со столбцом строки типа. Я хочу выполнить следующую миграцию:

class ChangeColumnToBoolean < ActiveRecord::Migration
    def up
        change_column :users, :smoking, :boolean
    end
end

Когда я запускаю это, я получаю следующую ошибку

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

Я знаю, что могу выполнить эту миграцию, используя чистый SQL, но все же было бы лучше, если бы я мог сделать это с помощью Rails. Я прошел через код Rails и, похоже, не имеет такой возможности, но, возможно, кто-то знает способ?

Меня не интересуют: - чистый SQL - удаление столбца - создание другого столбца, преобразование данных, удаление оригинала, а затем переименование

4b9b3361

Ответ 1

Поскольку я использую Postgres, на данный момент я пошел с SQL-решением. Используемый запрос:

    execute 'ALTER TABLE "users" ALTER COLUMN "smoking" TYPE boolean USING CASE WHEN "flatshare"=\'true\' THEN \'t\'::boolean ELSE \'f\'::boolean END'

Он работает только в том случае, если у вас есть поле, заполненное строками истинного/ложного типа (например, генерация коллекции переключателей по умолчанию с принудительным булевым типом)

Ответ 2

Если ваши строки в столбце smoking уже имеют допустимые логические значения, следующий оператор изменит тип столбца без потери данных:

change_column :users, :smoking, 'boolean USING CAST(smoking AS boolean)'

Аналогично, вы можете использовать этот оператор для приведения столбцов в целое число:

change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'

Я использую Postgres. Не уверен, работает ли это решение для других баз данных.

Ответ 3

Не все базы данных допускают изменение типа столбца, обычно используемый подход заключается в добавлении нового столбца требуемого типа, переносе любых данных, удалении старого столбца и переименовании нового.

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

Ответ 4

Итак, правильно для boolean в postgres:

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

и вы можете добавить еще несколько условий WHEN - THEN в ваше выражение

Для других серверов баз данных выражение будет построено на основе синтаксиса для вашего сервера базы данных, но принцип тот же. Только ручного алгоритма преобразования, полностью без SQL, недостаточно.

Путь с синтаксисом change_column :table, :filed, 'boolean USING CAST(field AS boolean)' подходит только для содержимого поля: true/false/null