运行 在指定环境下以编程方式进行 Rake 任务
Run Rake task programmatically with specified environment
我在 Rails (3) 应用程序上用我的 Ruby 设置第二个数据库,所以我想创建一个 rake 任务来创建第二个开发数据库。我正在尝试覆盖 rake db:create
任务,以便它完成我需要的所有数据库创建。但是,我似乎找不到合适的方法来执行此任务。我尝试了几种方法 - 从 URL:
建立到数据库的连接
# remove db:create from the list of rake tasks in order to override it
db_create = Rake.application.instance_variable_get('@tasks').delete('db:create')
namespace :db do
task :create do
if Rails.env == "development"
# database.yml contains an entry for secondary_development, this works, as confirmed from rails console
ActiveRecord::Base.establish_connection "postgresql://localhost/secondary_development"
Rake::Task["db:create"].invoke # this does nothing
end
# invoke original db_create task - this works
db_create.invoke
end
end
另一种方法是:
# remove db:create from the list of rake tasks in order to override it
db_create = Rake.application.instance_variable_get('@tasks').delete('db:create')
namespace :db do
task :create do
if Rails.env == "development"
Rails.env = "secondary_development"
Rake::Task["db:create"].invoke
end
# invoke original db_create task - this doesn't work like this
db_create.invoke
end
end
这一次只有 secondary_development
db:create
可以正常工作并且数据库已按需创建,但不再创建development
数据库使用这种方法。
根据我在其他地方找到的一个答案,我认为有必要重新启用该任务,但这并没有改变任何东西,而且似乎不是问题所在。
最后,一个行之有效的方法是:
# remove db:create from the list of rake tasks in order to override it
db_create = Rake.application.instance_variable_get('@tasks').delete('db:create')
namespace :db do
task :create do
if Rails.env == "development"
system("rake db:create RAILS_ENV=secondary_development")
end
db_create.invoke
end
end
这里唯一的问题是,因为 rake 任务是通过 system
执行的 运行,所以 Rails 应用程序必须在执行之前加载,所以我实际上是在加载完全应用两次只是为了 运行 任务 - 当我将测试数据库添加到组合中时,这将是 3 次。
因此,实际问题:
是否可以在指定环境中以编程方式运行 Rake::Task["..."]
?
为什么在创建数据库时ActiveRecord::Base.establish_connection
不是这样工作的?当从 Rails 控制台 运行ning 时,我成功了。
我设法找到了解决办法。我相信原因是.invoke
不会总是调用任务,但它会先判断是否有必要。鉴于 rake db:create
在同一任务中多次出现 运行,.invoke
认为后续调用是不必要的,因此不会 运行 它们。对于所需的行为,应改用 .execute
。
# remove db:create from the list of rake tasks in order to override it
db_create = Rake.application.instance_variable_get('@tasks').delete('db:create')
namespace :db do
task :create do
if Rails.env == "development"
Rails.env = "secondary_development"
Rake::Task["db:create"].execute # execute rather than invoke
end
# Reset the Rails env to 'development', otherwise it remains as 'secondary_development', which is not what we want (or move this above the if)
Rails.env = "development"
db_create.execute
end
end
我在 Rails (3) 应用程序上用我的 Ruby 设置第二个数据库,所以我想创建一个 rake 任务来创建第二个开发数据库。我正在尝试覆盖 rake db:create
任务,以便它完成我需要的所有数据库创建。但是,我似乎找不到合适的方法来执行此任务。我尝试了几种方法 - 从 URL:
# remove db:create from the list of rake tasks in order to override it
db_create = Rake.application.instance_variable_get('@tasks').delete('db:create')
namespace :db do
task :create do
if Rails.env == "development"
# database.yml contains an entry for secondary_development, this works, as confirmed from rails console
ActiveRecord::Base.establish_connection "postgresql://localhost/secondary_development"
Rake::Task["db:create"].invoke # this does nothing
end
# invoke original db_create task - this works
db_create.invoke
end
end
另一种方法是:
# remove db:create from the list of rake tasks in order to override it
db_create = Rake.application.instance_variable_get('@tasks').delete('db:create')
namespace :db do
task :create do
if Rails.env == "development"
Rails.env = "secondary_development"
Rake::Task["db:create"].invoke
end
# invoke original db_create task - this doesn't work like this
db_create.invoke
end
end
这一次只有 secondary_development
db:create
可以正常工作并且数据库已按需创建,但不再创建development
数据库使用这种方法。
根据我在其他地方找到的一个答案,我认为有必要重新启用该任务,但这并没有改变任何东西,而且似乎不是问题所在。
最后,一个行之有效的方法是:
# remove db:create from the list of rake tasks in order to override it
db_create = Rake.application.instance_variable_get('@tasks').delete('db:create')
namespace :db do
task :create do
if Rails.env == "development"
system("rake db:create RAILS_ENV=secondary_development")
end
db_create.invoke
end
end
这里唯一的问题是,因为 rake 任务是通过 system
执行的 运行,所以 Rails 应用程序必须在执行之前加载,所以我实际上是在加载完全应用两次只是为了 运行 任务 - 当我将测试数据库添加到组合中时,这将是 3 次。
因此,实际问题:
是否可以在指定环境中以编程方式运行 Rake::Task["..."]
?
为什么在创建数据库时ActiveRecord::Base.establish_connection
不是这样工作的?当从 Rails 控制台 运行ning 时,我成功了。
我设法找到了解决办法。我相信原因是.invoke
不会总是调用任务,但它会先判断是否有必要。鉴于 rake db:create
在同一任务中多次出现 运行,.invoke
认为后续调用是不必要的,因此不会 运行 它们。对于所需的行为,应改用 .execute
。
# remove db:create from the list of rake tasks in order to override it
db_create = Rake.application.instance_variable_get('@tasks').delete('db:create')
namespace :db do
task :create do
if Rails.env == "development"
Rails.env = "secondary_development"
Rake::Task["db:create"].execute # execute rather than invoke
end
# Reset the Rails env to 'development', otherwise it remains as 'secondary_development', which is not what we want (or move this above the if)
Rails.env = "development"
db_create.execute
end
end