Rails миграция для изменения столбца

327

У нас есть script/generate migration add_fieldname_to_tablename fieldname:datatypeсинтаксис для добавления новых столбцов в модель.

В той же строке, у нас есть сценарий / генерировать для изменения типа данных столбца? Или я должен написать SQL прямо в моей миграции?

Я хочу изменить столбец с datetimeна date.

papdel
источник

Ответы:

549

Я думаю, что это должно работать.

change_column :table_name, :column_name, :date
Алекс Корбан
источник
13
@b_ayan: насколько я знаю, единственные волшебные слова в названиях миграции - это «добавить» и «удалить».
Алекс Корбан
1
Вроде рельсов нуб тут, но… я понимаю ответ, но не комментарии к этому ответу. Разъяснения приветствуются :)
Алан Х.
7
Когда вы создаете миграцию, вы даете ей имя (например, add_fieldname_to_tablename в вопросе выше). Если он начинается с «добавить» или «удалить», то миграция будет автоматически заполнена кодом для добавления или удаления столбцов, что спасет вас от написания этого кода самостоятельно.
Алекс Корбан
6
Также стоит иметь в виду, что вы должны заменить обычное changeдействие на отдельное upи downдействия, так как change_columnэто необратимая миграция, которая вызовет ошибку, если вам потребуется откат.
DaveStephens
1
@QPaysTaxes вверх должен содержать то, что вы хотите изменить столбец с и на, а вниз должен содержать, как отменить это изменение.
DaveStephens
98

Вы также можете использовать блок, если у вас есть несколько столбцов для изменения в таблице.

Пример:

change_table :table_name do |t|
  t.change :column_name, :column_type, {options}
end

См. Документацию API для класса Table для более подробной информации.

Джон
источник
88

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

Если tablename - это имя вашей таблицы, fieldname - это имя вашего поля, и вы хотите изменить дату с даты на дату, вы можете написать миграцию для этого.

Вы можете создать новую миграцию с помощью:

rails g migration change_data_type_for_fieldname

Затем отредактируйте миграцию, используя change_table:

class ChangeDataTypeForFieldname < ActiveRecord::Migration
  def self.up
    change_table :tablename do |t|
      t.change :fieldname, :date
    end
  end
  def self.down
    change_table :tablename do |t|
      t.change :fieldname, :datetime
    end
  end
end

Затем запустите миграцию:

rake db:migrate
Райан
источник
32

Как я обнаружил в предыдущих ответах, для изменения типа столбца необходимо выполнить три шага:

Шаг 1:

Создайте новый файл миграции, используя этот код:

rails g migration sample_name_change_column_type

Шаг 2:

Перейдите в /db/migrateпапку и отредактируйте созданный вами файл миграции. Есть два разных решения.

  1. def change
        change_column(:table_name, :column_name, :new_type)
    end

2.

    def up
        change_column :table_name, :column_name, :new_type
    end

    def down
        change_column :table_name, :column_name, :old_type
    end

Шаг 3:

Не забудьте выполнить эту команду:

rake db:migrate

Я проверил это решение для Rails 4, и оно работает хорошо.

Абузар Раджаби
источник
1
На шаге 2 первый сбой после запуска rake db: rollback, я рекомендую проверить второй
Feuda
Существует ли соглашение о рельсах, которое позволяет более или менее сделать все, чтобы создать файл миграции, не переходя к нему, а затем редактировать его?
BKSpurgeon
@BKSpurgeon Да, проверьте документацию здесь: edgeguides.rubyonrails.org/active_record_migrations.html
Абузар Раджаби,
12

С рельсами 5

Из направляющих рельсов :

Если вы хотите, чтобы миграция сделала что-то, что Active Record не знает, как отменить, вы можете использовать reversible:

class ChangeTablenameFieldname < ActiveRecord::Migration[5.1]
  def change
    reversible do |dir|
      change_table :tablename do |t|
        dir.up   { t.change :fieldname, :date }
        dir.down { t.change :fieldname, :datetime }
      end
    end
  end
end
Мистер тао
источник
8

Просто создайте миграцию:

rails g migration change_column_to_new_from_table_name

Обновите миграцию так:

class ClassName < ActiveRecord::Migration
  change_table :table_name do |table|
    table.change :column_name, :data_type
  end
end

и наконец

rake db:migrate
Вивек Шарма
источник
2

Другой способ изменить тип данных с помощью миграции

Шаг 1: Вам нужно удалить ошибочное имя поля типа данных, используя миграцию

например:

rails g migration RemoveFieldNameFromTableName field_name:data_type

Здесь не забудьте указать тип данных для вашего поля

Шаг 2: Теперь вы можете добавить поле с правильным типом данных

например:

rails g migration AddFieldNameToTableName field_name:data_type

Вот и все, теперь ваша таблица будет добавлена ​​с правильным полем типа данных, Happy ruby ​​coding!

prasanthrubyist
источник
2

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

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

/app/models/table.rb
  ...
  def string_to_date
    update(new_date_field: date_field.to_date)
  end

  def date_to_string
    update(old_date_field: date_field.to_s)
  end
  ...
    def up
        # Add column to store converted data
        add_column :table_name, :new_date_field, :date
        # Update the all resources
        Table.all.each(&:string_to_date)
        # Remove old column
        remove_column :table_name, :date_field
        # Rename new column
        rename_column :table_name, :new_date_field, :date_field
    end

    # Reversed steps does allow for migration rollback
    def down
        add_column :table_name, :old_date_field, :string
        Table.all.each(&:date_to_string)
        remove_column :table_name, :date_field
        rename_column :table_name, :old_date_field, :date_field
    end
Себастьян Шолль
источник
0

Чтобы завершить ответы в случае редактирования значения по умолчанию :

В вашей консоли рельсы:

rails g migration MigrationName

В миграции:

  def change
    change_column :tables, :field_name, :field_type, default: value
  end

Будет выглядеть так:

  def change
    change_column :members, :approved, :boolean, default: true
  end
Gregdebrick
источник