【问题标题】:How to know that a rake task has been run in rails?如何知道 rake 任务已在 rails 中运行?
【发布时间】:2016-06-03 18:47:29
【问题描述】:

我在我的 Rails 应用程序中进行了迁移,我希望仅在运行特定 rake 任务时才运行该迁移,否则我会丢失大量数据。以下是我想做的事情:

if has_rake_task_been_run?
  remove_column :transactions, :paid_by
end

目前,我无论如何都找不到,而不是手动确保这件事。有什么解决办法吗?

【问题讨论】:

  • 这味道很重。为什么迁移依赖于 rake 任务?您的架构不应依赖于您的代码。上面提到的 rake 任务负责什么?
  • 除非您将该信息存储在某处,否则您无法知道它是否已运行。就像您从任务中写入的文件或数据库,然后签入迁移。我假设在删除列之前需要 rake 任务来迁移数据?也许您可以在纯 SQL 中检查(即如果列不为空或类似)?然后才删除列?这将使您的迁移“独立”
  • @BroiSatse 我正在删除迁移中的一列,但在删除该列之前,我需要复制该列中的值,并填充一个新列。这就是为什么我需要在触发迁移之前确保任务已经运行。
  • @BilalMaqsood - 在这种情况下,将代码从您的任务移动到您的迁移 - 这称为数据迁移并且非常常见。 Rake 任务主要用于可重复的任务。另请注意,即使您设法在迁移中对其进行检查,迁移也会被标记为已执行,并且即使您的 rake 任务稍后完成也不会再次运行。
  • @pascalbetz 是的,这是有道理的。我将检查所需任务已通过 ruby​​ 代码运行的迁移,然后让迁移运行。

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


【解决方案1】:

使用 rake 任务进行数据迁移是一个非常冒险的想法。不这样做的几个原因:

  1. 即使您设法查明您的 rake 任务是否已完成,您的迁移仍将被标记为已完成,您将无法重播它。唯一的办法是在迁移中引发异常。

    不,您也无法回滚该迁移。如果 rake 任务在迁移运行后完成,回滚将尝试添加已经存在的列。

  2. 新开发人员从头开始设置数据库将变得非常痛苦,因为他们需要知道何时运行哪些 rake 任务。更不用说rake db:migrate 执行所有迁移。

  3. 你正在用不可重用的任务污染你的 rake 任务列表

您所做的似乎只是常规的数据迁移,因此您的 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,它将无法正常工作(我犯过一次这个错误,花了一段时间才找出问题所在)。解决方法是在迁移类之外定义它,但是这些类在所有迁移中都可用,并且可能会受到实际模型代码的影响(尤其是在预加载所有模型的生产环境中)。简而言之,我目前仍在研究如何使用 STI 进行数据迁移。

【讨论】:

    【解决方案2】:

    如果有人来这里,我们成功地使用了after_party rails 库。通过简单的机制,该库维护已执行的 rake 任务,并且执行迁移任务变得容易。

    【讨论】:

      猜你喜欢
      • 2011-08-04
      • 2015-01-08
      • 2012-06-25
      • 2010-10-09
      • 2019-04-13
      • 2016-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多