如何知道rake任务已在rails中运行?

时间:2016-02-22 11:06:16

标签: ruby-on-rails ruby ruby-on-rails-4 rake rake-task

我在我的Rails应用程序中进行了迁移,我只想在运行特定的rake任务时运行,否则我将丢失一堆数据。以下是我想做的事情:

if has_rake_task_been_run?
  remove_column :transactions, :paid_by
end

目前,我无法找到,而不是手动确认此事。有什么工作吗?

2 个答案:

答案 0 :(得分:3)

使用rake任务进行数据迁移是一个非常危险的想法。有几个理由不这样做:

  1. 即使您设法确定您的佣金任务是否已完成,您的迁移仍会标记为已完成,但您无法重播。唯一的方法是在迁移过程中引发异常。

    不,你也无法回滚那次迁移。如果rake任务在迁移运行后完成,则回滚将尝试添加现有列。

  2. 新开发人员从头开始设置数据库会变得很痛苦,因为他们需要知道哪些rake任务要运行。没有提到rake db:migrate执行所有迁移。

  3. 您使用不可重复使用的任务污染您的佣金任务列表

  4. 您所做的似乎只是常规的数据迁移,因此您的rake任务完成的所有工作实际上都应该是您迁移的一部分。这甚至可以让你进行可逆的数据迁移(在大多数情况下)。

    但请注意,数据迁移并不像常规的仅计划迁移那么简单。因为您的迁移应该完全独立于您的代码(因为它们将来会工作,即使迁移的模型已从您的代码库中完全删除),因此通常的做法是重新定义您将要在迁移中使用的模型(仅迁移所需的位数)。不幸的是,这听起来并不那么简单,老实说,我仍然在寻找一个完美的解决方案。到目前为止我见过的最好的事情很简单(我假设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,它将无法正常工作(我曾经犯过一次错误,需要一段时间才能找到什么&#39;错了)。解决方法是在迁移类之外定义它,但是这些类在所有迁移中都可用,并且可能会受到实际模型代码的影响(特别是在预加载所有模型时的生产中)。简而言之,我目前仍在研究使用STI进行数据迁移。

答案 1 :(得分:2)

万一有人来了,我们成功使用了after_party rails库。通过简单的机制,该库可以维护已执行的rake任务,并且可以轻松执行迁移任务。