Railsで使うRakeタスクは大きくわけて3種類あり、普通はこの順番で定義されることになっている。
- gemのタスク
- アプリケーション固有のタスク
- Railsのタスク
まずソースコードを読んでみた。
Rakefile
# Rakefile
require File.expand_path('../config/application', __FILE__)
Rails.application.load_tasks
config/application.rb
を読んでからRails.application.load_tasks
を呼ぶ。
Rails.application.load_tasks
Rails.application.load_tasks
はrailtie
のRails::Engine
に定義されている。
# railties-4.1.0/lib/rails/engine.rb
def load_tasks(app=self)
require "rake"
run_tasks_blocks(app)
self
end
この中で呼ばれているrun_tasks_blocks
はEngine
のサブクラスである、Rails::Application
に定義されていて、実装は次のようになっている。
# railties-4.1.0/lib/rails/application.rb
def run_tasks_blocks(app) #:nodoc:
railties.each { |r| r.run_tasks_blocks(app) }
super
require "rails/tasks"
task :environment do
ActiveSupport.on_load(:before_initialize) { config.eager_load = false }
require_environment!
end
end
このうちの最初の3行が最初に挙げた3種類のタスクの定義に相当する。
- gemのタスク
- アプリケーション固有のタスク
- Railsのタスク
gemのタスク
gem用のタスクというものがある。たとえばdb:migrate
はActiveRecordのRakeタスクで、このタスクはactiverecord-4.1.0/lib/active_record/railties/databases.rake
に定義されている。これをここではgem用のタスクと呼ぶことにする。
gem用のタスクはRailtieを介して定義されている。
まずActiveRecord::Railtie
のクラス定義でスーパークラスであるRails::Railtie
のrake_task
メソッドが呼ばれ、タスクの定義がブロックとして渡されている。
# activerecord-4.1.0/lib/active_record/railtie.rb
rake_tasks do
# ... 略
load "active_record/railties/databases.rake"
end
このrake_tasks
メソッドは単にブロックをArrayとして取っておくだけのものとなっている。
def rake_tasks(&blk)
@rake_tasks ||= []
@rake_tasks << blk if blk
@rake_tasks
end
ここで取っておいたブロックは、RailsのRakeファイルから呼び出されるload_tasks
において、このコードの部分
railties.each { |r| r.run_tasks_blocks(app) }
で実行され、各gemのタスクが定義されることとなる。
アプリケーション固有のタスク
アプリケーション固有のタスクというのは、lib/tasks/*.rake
という名前で定義すアプリケーション専用のRakeタスクのことを言っている(勝手に呼んでいる)。
このファイルがどこで読み込まれているかを知るためにはRails::Application.run_tasks_block
中のsuper
という呼び出しを見ていく必要がある。super
であるRails::Engine.run_tasks_blocks
のコードは次のとおり。
def run_tasks_blocks(*) #:nodoc:
super
paths["lib/tasks"].existent.sort.each { |ext| load(ext) }
end
ここでのsuper
は@rake_tasks
が持っているコードブロックを実行するもので、gem用のタスクのときに使われているがRailsアプリケーションとしては使われていないはず。
アプリケーション固有のタスクはメソッド2行目のこの部分、paths["lib/tasks"].existent.sort.each { |ext| load(ext) }
でロードされる。コードは見たまんま。
Railsのタスク
まだ見ていない最後の行でRailsのタスクが定義される。
require "rails/tasks"
requireされているtasks.rb
にはタスクが定義されているファイルを複数ロードするというコードが書かれている。
# railties-4.1.0/lib/rails/tasks.rb
# Load Rails Rakefile extensions
%w(
annotations
documentation
framework
log
middleware
misc
routes
statistics
tmp
).each do |task|
load "rails/tasks/#{task}.rake"
end
# railties-4.1.0/lib/rails/tasks/routes.rake
desc 'Print out all defined routes in match order, with names. Target specific controller with CONTROLLER=x.'
task routes: :environment do
all_routes = Rails.application.routes.routes
require 'action_dispatch/routing/inspector'
inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
puts inspector.format(ActionDispatch::Routing::ConsoleFormatter.new, ENV['CONTROLLER'])
end
rake routes
やrake stats
などはここで定義されているということがわかる。
Rakeタスクの削除の可否
RailsのRakeタスクを上書き・再定義するには - ぴよログ
すでにロードされているRakeタスクを削除する方法がある。この記事ではアプリケーション固有のタスクを書くときに既存のタスク削除して上書きするという方法にトライした。
この記事でも書いたが、アプリケーション固有のタスクを定義する段階では、Railsのタスクは削除できない。先ほど見たとおりRailsのタスクは最後に読み込まれるからだ。
Rails::Application.run_tasks_blocks
自体をモンキーパッチしてしまうなどの方法は無くはないかもしれないが、似たようなコードをコピーしてくることになるのであまりスマートではない。となると、きれいに書く方法はないのかもしれない。