Переход от двухстрочной переменной yes / no к одной логической переменной в rails?

#ruby-on-rails #database-migration #ruby-on-rails-5.1

#ruby-on-rails #база данных-миграция #ruby-on-rails-5.1

Вопрос:

Вопрос касается миграции базы данных rails.

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

 create_table "table_name", force: :cascade do |t|
    ... 

    t.string "yes_boolvar"
    t.string "no_boolvar"
    ...

end
  

Мне нужно преобразовать ее в одну логическую переменную следующим образом:

     t.boolean "boolvar"
  

Я подумал о переименовании ‘yes_boolvar’, изменении его типа со string на boolean, а затем удалении столбца ‘no_boolvar’ на основе некоторых показаний, например, следующего:

  t.rename :yes_boolvar,
          :boolvar
 t.change :boolvar,
          :boolean
 t.remove :no_boolvar
  

Однако при копировании значения переменной будет учитываться только значение истинности ‘yes_ *’, а не ‘no_ *’. Есть ли способ успешно перенести var, чтобы были приняты во внимание истинностные (или нулевые) значения обоих переменных.

Ответ №1:

Это зависит от вашего приложения.

Если никто не может обновить эти значения (т. Е. Это не поле в профиле пользователя), то вы можете:

  1. создать дамп базы данных
  2. запустите миграцию
  3. выполните код, который заполнит boolvar

Другим решением является перенос данных в 3 этапа:

  1. при первой миграции столбец переименовывается
  2. вторая миграция переносит данные
  3. третья миграция удаляет no_boolvar столбец

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

Ответ №2:

Я рекомендую вам выполнить 3 миграции. Для начала создайте миграцию, добавив boolean: :boolvar

 class AddBoolvarToTableName < ActiveRecord::Migration
  def up
    add_column :table, :boolvar, :boolean
  end

  def down
    remove_column :table, :boolvar  
  end
end
  

После создайте новую миграцию для обработки данных:

 class RepopulateBooleanValues < ActiveRecord::Migration[5.0]
  def change
    YourClass.all.each do |record|
      # put the logic here like:
      record.boolvar = record.yes_boolvar == 'true' 
      # or 
      record.boolvar = record.not_boolvar == 'false'
      # I'am not sure whats the content of yes_boolvar and not_boolvar, elaborate the logic here
      record.save
    end
  end
end
  

Чтобы завершить это, просто создайте новую миграцию, удалив yes_boolvar и no_boolvar .

Ответ №3:

Примерно такую миграцию я бы написал (я не запускал код, но она должна сработать):

 # This ensures the migration to work
# regardless the customizations on your original model
class TempModel < ActiveRecord::Base
  self.table_name = 'table_name'
end

class MyMigration < ActiveRecord::Migration[5.0]
  def up
    add_column :table_name, :boolvar, :boolean

    TempModel.reset_column_information
    TempModel.find_each do |record|
      # Decide some logic here about how to migrate values from yes_boolvar
      # and no_boolvar columns to boolvar column
      boolvar_value = record.yes_boolvar || !record.no_boolvar
      record.update_column :boolvar, boolvar_value
    end

     remove_column :table_name, :yes_boolvar
     remove_column :table_name, :no_boolvar
  end

  def down
    add_column :table_name, :yes_boolvar, :string
    add_column :table_name, :no_boolvar, :string

    TempModel.reset_column_information
    TempModel.find_each do |record|
      # Decide some logic here about how to handle yes_boolvar
      # and no_boolvar values
      record.update_columns yes_boolvar: record.boolvar,
                            no_boolvar: !record.boolvar
    end

    remove_column :table_name, :boolvar
  end
end