我正在将使用 Postgresql 模式(search_path)的多租户的 Rails 应用程序迁移到使用多数据库/水平共享中内置的 Rails。在此过程中,我需要能够覆盖
db:..
任务,例如 rails db:migrate
、rails db:migrate:rollback
等,以便针对我的所有模式运行。
我已经尝试过:
#config/initializers/migrations.rb
module Migrations
module DatabaseTasks
def migrate(*)
["a", "b", "c"] do |schema|
ActiveRecord::Base.connection.schema_search_path=schema
puts "------------- migrating: #{schema} --------------"
super
end
end
end
end
ActiveSupport.on_load(:active_record) do
ActiveRecord::Tasks::DatabaseTasks.singleton_class.prepend(Migrations::DatabaseTasks)
end
这对于
rails db:migrate
非常有用 - 但它不适用于 rails db:migrate:down
或 rails db:rollback
,因为它们不调用 ActiveRecord::Tasks::DatabaseTasks.migrate
请参阅:https://github.com/rails/rails/blob/bc2f390f7d2a96030532f41c08205f159e05af10/activerecord /lib/active_record/railties/databases.rake#L260
我也尝试过覆盖 rake 任务本身:
# tasks/my_custom_db_tasks.rake
namespace :db do
task migrate: :environment do |_task, _args|
# Get a reference to the original db:migrate task
original_migrate_task = Rake::Task['db:migrate']
# Run the original migration task the specified number of times
["a", "b", "c"] do |schema|
ActiveRecord::Base.connection.schema_search_path=schema
puts "---------- migrating: #{schema} --------------"
original_migrate_task.invoke
original_migrate_task.reenable
end
end
end
但是对所有任务来说都很麻烦,而且它也没有真正起作用,因为我尝试覆盖任务定义的方式似乎有问题。
我的问题是: 一般挂钩
db:...
测试并多次运行原始/“super
”任务的最佳方法是什么?
可以“增强”耙子任务
我之前使用过的一个例子如下:
Rake::Task['db:migrate'].enhance ['db:my_task_before_migrate']
Rake::Task['db:rollback'].enhance ['db:my_task_before_rollback']
Rake::Task['db:migrate'].enhance do
Rake::Task['db:my_task_after_migrate'].invoke
end
Rake::Task['db:rollback'].enhance do
Rake::Task['db:my_task_after_rollback'].invoke
end
请注意这里作为参数传递和作为块传递之间的区别。 当作为参数传递时,传递的任务将在您增强的任务之前运行。 将其作为块传递时,正在调用的任务将在
增强后运行。