[英]Get rake task name in initializer
我想知道,如果app实例是由rake
启动的,那么我尝试在initializers
捕获rake
任务名称。 例如,如果我运行rake db:migrate
我想要获取db:migrate
或类似的东西。 我试过这个;
[7] pry(main)> $0
=> "spring app | bilet18 | started 3 secs ago | development mode"
[8] pry(main)> ARGV
=> []
[9] pry(main)> Rake.application.top_level_tasks
=> []
但一切都是空的。
我能做什么? 请帮忙。
UPDATE
如果添加Rakefile行就好
ENV["RAKE_CURRENT_TASKS"] = Rake.application.top_level_tasks.join(' ')
然后在将来你将能够抓住它。但这个解决方案对我不好,我需要更早地抓住rake任务名称
除非你停止使用Spring , 否则这里提出的其他答案都不会有效,因为Spring会改变rake任务被大量调用的方式。
使用Spring时,正在运行的命令将使用UNIX套接字移交给Spring服务器进程,不幸的是,Spring服务器在初始化rails环境后读取此套接字以获取命令及其参数。 因此,在rails初始化期间,使用Spring时似乎无法获取命令及其参数(例如rake任务名称),因为Spring本身还不知道! 即使是Spring提供的after_fork
钩子也无济于事,因为它也是在 rails初始化之后运行的。
可以在Spring源代码中看到证据。 它是一个serve
方法 ,Spring从套接字中获取命令的ARGV
,自行分叉并运行命令。 该方法的相关部分如下:
def serve(client)
# ... getting standard input / output streams from the client socket
# this is where rails initialization occurs
preload unless preloaded?
# this is where Spring gets the command name and it's ARGV and environment
args, env = JSON.load(client.read(client.gets.to_i)).values_at("args", "env")
command = Spring.command(args.shift)
# ...
# fork and run the command
pid = fork {
# ...
# run the command
ARGV.replace(args)
$0 = command.exec_name
# ...
# run the after_fork hook
invoke_after_fork_callbacks
command.call
}
# ...
end
rails初始化程序在preload
方法中运行 ,该方法在从套接字读取命令名之前运行。 在初始化之后,在fork
块中也设置$0
和ARGV
变量。
因此,除非你明显地修补了Spring(用你自己的方法替换了serve
方法,但是你需要自己处理套接字), 你需要停止在Spring环境中调用你的rake任务 。 如果rake
命令是RAILS_ROOT/bin/
目录中的binstub,则需要使用spring binstup --remove rake
删除binstub。
只有这样,我相信,您可以在其他答案中使用其中一种解决方案。
您是否在任务中包含了=> :environment
? 例如
task :sometask => :environment do
...
end
否则,在运行rake任务时,初始化程序不会运行
有两种方法可以达到你想要的效果,
1,不使用spring
,只需运行:
spring binstub --remove --all
然后运行你的rake任务。
2,使用弹簧:
创建一个spring.rb文件config/spring.rb
after_fork
并使用after_fork
Spring.after_fork do
# run your code here
# you have access to ARGV
binding.pry
end
我相信这可以满足您的需求。 任务名称还应包括命名空间。
配置/初始化/ rake.rb
module Rake
class Application
attr_accessor :current_task
end
class Task
alias :old_execute :execute
def execute(args=nil)
Rake.application.current_task = @name
old_execute(args)
end
end #class Task
end #module Rake
车型/ something.rb:
class Something < ActiveRecord::Base
puts Rake.application.current_task
end
LIB /任务/ some_task.rake:
require 'rake'
namespace :ns do
task :some_task => :environment do
Something.all.to_a
end
end
安慰:
rake ns:some_task
ns:some_task
也有效:
bundle exec rake ns:some_task
ns:some_task
您可以使用Rake::Task#enhance
来重新定义任务,以便在调用原始任务之前创建变量,但这看起来有点混乱,您将不得不担心如何处理以下任务:environment
和:default
。
我认为最简单的方法可能是扩展Rake::Task#invoke
方法以添加一个全局变量,然后可以在初始化程序中或从您想要的任何地方访问该变量。
这是一个非常快速的脏例子,你可以在Rakefile
做:
module RakeTaskName
def invoke(*args)
$rake_task_name = name
super *args
end
end
Rake::Task.send :prepend, RakeTaskName
然后,在初始化程序中,您可以执行以下操作:
if defined? $rake_task_name
puts "Running from rake task: #{$rake_task_name}"
end
编辑
这是一个带有此代码和1迁移的新rails项目 。 输出如下所示:
Running from rake task: db:migrate
== 20160411150810 CreateFoo: migrating ========================================
-- create_table(:foos)
-> 0.0010s
== 20160411150810 CreateFoo: migrated (0.0011s) ===============================
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.