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

Могут ли Rails Migrations использоваться для преобразования данных?

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

В моей миграции у меня это:

def.self up
    add_column :users, :age_text, :string

    users = User.find(:all)

    users.each do |u|
       u.age_text = convert_to_text(u.age)
       u.save
    end
end

def self.convert_to_text(number)
   #code here to convert 1 to 'one' etc
end

Но, похоже, он не работает, и что я пытаюсь сделать здесь даже с миграциями?

4b9b3361

Ответ 1

То, что вы пытаетесь сделать, возможно, и я бы сказал, что это правильно.

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

def.self up
    add_column :users, :age_text, :string

    User.reset_column_information 

    users = User.find(:all)

    users.each do |u|
       u.age_text = convert_to_text(u.age)
       u.save
    end
end

В отдельном примечании обратите внимание, что если ваша таблица большая, то при выполнении обновлений один за другим будет выполняться время looong. Будьте осторожны с этим.

Ответ 2

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

ОБЩЕЕ манипулирование данными в миграциях - идея BAD. Миграции с прямым доступом к модели могут зависеть, если изменяется логика модели.

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

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

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

Ответ 3

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

class ConvertCommentTextToText < ActiveRecord::Migration
  def up
    add_column :comments, :text_tmp, :text
    # copy text column
    execute <<-SQL
      update comments set text_tmp = text
    SQL
    remove_column :comments, :text
    rename_column :comments, :text_tmp, :text
  end

  def down
    add_column :comments, :text_tmp, :string
    # copy text column
    execute <<-SQL
      update comments set text_tmp = text
    SQL
    remove_column :comments, :text
    rename_column :comments, :text_tmp, :text
  end

end

И проверить это:

rake db:migrate
rake db:rollback
rake db:migrate

Ответ 4

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

Например, у меня есть миграция, которая настраивает множество таблиц поиска и других метаданных. Данные для этих таблиц заполняются на этом этапе. По мере изменения данных для этих таблиц поиска я создаю новые файлы YAML, хранящие метаданные, и загружаю эти файлы в последующие миграции (и отменяет эти YAMLS, перезагружая предыдущий файл YAML при выходе из версии миграции). Это довольно чисто. У меня есть файлы (в разных четко определенных папках в моем случае) с этими файлами:

002_setup_meta_data.rb
002_meta_data.yaml


007_change_meta_data.rb
007_meta_data.yaml

Если вы импортируете "производственные" данные из другой системы в транзакционные (нестатические) таблицы, я бы сказал, что использование миграции не подходит. Затем я буду следовать совету Брайана Хогана по использованию рейк-задач.