如何知道抽取任务已经 运行 在 rails?
How to know that a rake task has been run in rails?
我的 Rails 应用程序中有一个迁移,我想 运行 仅当特定的 rake 任务已经 运行 时,否则我会失去一个一堆数据。以下是我想做的事情:
if has_rake_task_been_run?
remove_column :transactions, :paid_by
end
目前,反正我是找不到了,只能手动保证这个东西了。有什么解决办法吗?
使用rake task进行数据迁移是一个非常冒险的想法。不这样做的几个原因:
即使您设法确定您的 rake 任务是否已完成,您的迁移仍将被标记为已完成并且您将无法重播它。唯一的解决办法是在您的迁移中引发异常。
不,您也无法回滚该迁移。如果 rake 任务在迁移 运行 后完成,回滚将尝试添加已经存在的列。
新开发人员从头开始设置数据库会变得非常痛苦,因为他们需要知道 运行 什么时候执行哪些 rake 任务。更不用说 rake db:migrate
执行所有迁移。
您正在用不可重复使用的任务污染您的 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,它就无法正常工作(我犯过一次这个错误,花了一段时间才找出问题所在)。解决方法是在迁移 class 之外定义它,但是这些 classes 在所有迁移中都可用,并且可能会受到您的实际模型代码的影响(尤其是在预加载所有模型的生产中).简而言之,我目前仍在研究使用 STI 进行数据迁移。
万一有人来这里,我们成功地使用了after_partyrails库。库通过简单的机制维护已经执行过的rake任务,迁移任务变得容易。
我的 Rails 应用程序中有一个迁移,我想 运行 仅当特定的 rake 任务已经 运行 时,否则我会失去一个一堆数据。以下是我想做的事情:
if has_rake_task_been_run?
remove_column :transactions, :paid_by
end
目前,反正我是找不到了,只能手动保证这个东西了。有什么解决办法吗?
使用rake task进行数据迁移是一个非常冒险的想法。不这样做的几个原因:
即使您设法确定您的 rake 任务是否已完成,您的迁移仍将被标记为已完成并且您将无法重播它。唯一的解决办法是在您的迁移中引发异常。
不,您也无法回滚该迁移。如果 rake 任务在迁移 运行 后完成,回滚将尝试添加已经存在的列。
新开发人员从头开始设置数据库会变得非常痛苦,因为他们需要知道 运行 什么时候执行哪些 rake 任务。更不用说
rake db:migrate
执行所有迁移。您正在用不可重复使用的任务污染您的 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,它就无法正常工作(我犯过一次这个错误,花了一段时间才找出问题所在)。解决方法是在迁移 class 之外定义它,但是这些 classes 在所有迁移中都可用,并且可能会受到您的实际模型代码的影响(尤其是在预加载所有模型的生产中).简而言之,我目前仍在研究使用 STI 进行数据迁移。
万一有人来这里,我们成功地使用了after_partyrails库。库通过简单的机制维护已经执行过的rake任务,迁移任务变得容易。