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