rails には script/breakpointer というスクリプトを使うと アプリケーションを止めたい場所で止めて、DRb (druby) 経由で irb 接続して調べることはできるのだが、 irb ではなくステップ実行をしたい。
というわけで、以下のようなコマンドを打ってみる。
$ ruby -rdebug script/server Debug.rb Emacs support available. script/server:2:require File.dirname(__FILE__) + '/../config/boot' (rdb:1) b HogeController.list script/server:2:uninitialized constant HogeController
rails は実行時に動的に Controller をロードするので、 この時点ではまだ HogeController は読み込まれていないようだ。
というわけで、ソースファイル名と行番号でブレークポイントを指定して みたいんだけど、ソースファイル名の指定の仕方がよくわからん。 カレントディレクトリからの相対パスで指定したら良いのか、 絶対パスなのか、basename だけで良いのか?
実際に試してみたら、相対パスでも絶対パスでも basename でもダメ。
で、さんざん悩んで試行錯誤して rails アプリをブラウザ上で 実行していてエラーがおきたときに 表示されるスタックトレースに出てくるパスからヒントを得て、 こんな感じのパスを書くとやっと breakpoint で止めることができて、 step 実行ができるようになった。
(rdb:1) b ./script/../config/../app/controllers/hoge_controller.rb:11
なるほど。おそらく script/server の中で
require File.dirname(__FILE__) + '/../config/boot'
ってな感じで boot を require して、その中で
RAILS_ROOT は ".."
って定義されてて、そこから initializer の中で app の下へ パスが通されるので、こんなパスになっちゃうってことかな?
RAILS_ROOT を定義しておけば、もう少し覚えやすいパスになるんだろうけど、 プロジェクト作るたびに定義するのも面倒なのでとりあえずこのまま使うことにする。
あ、ひとつ注意点。FastCGI で動かしていると、break できなかった。 FastCGI を入れていない人は自動的に webrick になるんだと思うが、 私は既に FastCGI を入れてしまっているので、script/server の後ろに 引数をつけて webrick で起動したら break することができた。
$ ruby -rdebug script/server webrick
UnitTest を debug.rb でデバッグ を書きました。