2016-02-22 5 views
0

У меня есть миграция в моем приложении Rails, который я бы хотел запустить, только если была выполнена конкретная задача rake, иначе я потеряю кучу данных. Ниже то, что я хотел бы сделать:Как узнать, что рейк-задача была запущена в рельсах?

if has_rake_task_been_run? 
    remove_column :transactions, :paid_by 
end 

В настоящее время я не мог найти в любом случае, вместо того, уверяя эту вещь вручную. Есть ли для этого какая-то работа?

+1

Это пахнет много. Почему миграция зависит от задачи рейка? Ваша схема никогда не должна зависеть от вашего кода. За что отвечает упомянутая задача рейка? – BroiSatse

+0

Вы не можете знать, была ли она выполнена, если вы не храните эту информацию где-нибудь. Как файл или БД, которые вы пишете из задачи, а затем проверьте миграцию. Я предполагаю, что задача рейка необходима для переноса данных, прежде чем вы сможете удалить столбец? Возможно, вы можете проверить это в чистом SQL (то есть, если столбец не является нулевым или похожим)? И только потом удалите столбец?Это сделало бы вашу миграцию «самосохраненной» –

+0

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

ответ

3

Использование рейк-задачи для переноса данных является чрезвычайно рискованной идеей. Пара причин, чтобы не делать этого:

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

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

  2. Настройка вашей базы данных с нуля новыми разработчиками станет болезненной, поскольку они должны будут знать, какие задачи грабли должны выполняться, когда. Не говоря уже о том, что rake db:migrate выполняет все миграции.

  3. Вы загрязняя список задач грабель с не многоразовыми задачами

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

Обратите внимание, что миграция данных не такая простая, как регулярные миграции только для схемы. Поскольку ваша миграция должна быть полностью независимой от вашего кода (поскольку они должны работать в будущем, даже если мигрированная модель полностью удалена из вашей кодовой базы), поэтому обычной практикой является переопределение моделей, которые вы собираетесь использовать в своих миграциях (только бит, необходимый для миграции). Это не так просто, как это звучит, к сожалению, и, честно говоря, я все еще ищу идеальное решение. Лучшее, что я видел до сих пор просто (я предполагаю, что paid_by раньше строка, и вы изменили его paid_by_id, который ссылается на пользователя):

class YOURMIGRATIONNAME < ActiveRecord::Migration 
    class Transaction < ActiveRecord::Base 
    belongs_to :paid_by, class_name: "User" 
    end 

    class User < ActiveRecord::Base 
    end 

    def up 
    add_column :transaction, :paid_by_id, :integer 

    Transaction.transaction do # for speed 
     Transaction.find_each do |t| 
     t.paid_by_id = User.find_by(username: t[:paid_by]) 
     t.save!   # Always banged save in migration! 
     end 
    end 

    remove_column :paid_by 
    end 

    def down 
    add_column :transaction, :paid_by, :string 

    Transactions.transaction do 
     Transaction.find_each do |t| 
     t[:paid_by] = t.paid_by && t.paid_by.username 
     t.save! 
     end 
    end 

    remove_column :transactions, :paid_by_id 

end 

Единственный недостаток использования кода выше, что это не сработает, если какая-либо из этих моделей использует STI (я однажды совершил эту ошибку, потребовалось некоторое время, чтобы выяснить, что не так). Работа заключается в том, чтобы определить ее за пределами класса миграции, но тогда эти классы доступны во всех миграциях и могут быть затронуты вашим фактическим кодом модели (особенно в производстве, когда все модели предварительно загружены). Короче говоря, миграция данных с STI - это то, что я сейчас изучаю.

Смежные вопросы