2009-12-11 3 views
0

Предположим, у вас есть «lineitems», и вы использовали для определения «make» off line_item.Перенос данных при миграции Rails

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

Затем вы хотите удалить столбец make из таблицы line_items, но для каждого line_item с make вы хотите find_or_create_by (line_item.make).

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

Спасибо!

ответ

3

Я думаю, вы должны проверить, что Make.count равен полному уникальному make в lineitems перед удалением столбца, и поднять ошибку, если это не так. Поскольку миграции являются транзакционными, если они взрываются, схема не изменяется и миграция не помечена как выполненная. Поэтому вы можете сделать что-то вроде этого:

class CreateMakesAndMigrateFromLineItems < ActiveRecord::Migration 
    def self.up 
    create_table :makes do |t| 
     t.string :name 
     … 
     t.timestamps 
    end 

    makes = LineItem.all.collect(:&make).uniq 
    makes.each { |make| Make.find_or_create_by_name make } 
    Make.count == makes.length ? remove_column(:line_items, :make) : raise "Boom!" 

    end 

    def self.down 
    # You'll want to put logic here to take you back to how things were before. Just in case! 
    drop_table :makes 
    add_column :line_items, :make 
    end 
end 
+0

Транзакционные миграции доступны только в том случае, если поставщик базы данных поддерживает его. MySQL, например, не обеспечивает транзакционный DDL, поэтому оператор raise приведет к сбою миграции и оставит базу данных в противоречивом состоянии. – Cluster

+0

Если вы добавите в том, что говорит кластер, возможно, разделите его на две миграции, добавьте новый столбец в один и сделайте все, что вам нужно. Во втором, когда пыль осела, удалите все столбцы, которые вам больше не нужны. Это не идеально, но даст вам путь назад. – Ghoti

0

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

Для вашей ситуации создайте таблицу Make и добавьте make_id к линейному элементу. Затем для каждой позиции find_or_create с столбцом make на lineitem, задав возвращаемый идентификатор новому make_id на lineitem. Когда вы закончите, удалите старый столбец make из таблицы lineitem.