Ruby (Rails) でエンバグしたときのもがきかた
当てずっぽうで手直ししていると収拾がつかなくなるし、後で自分の書いたコード見る人にとってもよくないので、なるべく原因を論理的に究明し、解決していきます。 ということで、適当デバッガから脱すべく幾つか調べてみました。
■ その変数やメソッドが他に使われてる例を探す
プロジェクト内をgit grep
■ 自分のメソッド名を出力して足跡を探る
puts "========== #{self.class.name}##{__method__} ==========" or Rails.logger.debug "========== #{self.class.name}##{__method__} ==========" もっと派手 Rails.logger.info "\n==========\n========== #{self.class.name}##{__method__}\n==========\n"
これを通ってそうなメソッドに片っ端から入れまくる
■ RubyMineでは、Command+Clickでそのメソッドやクラス、オブジェクトの定義にジャンプできる
超便利
これだけのためだけにRubyMineを常につけているレヴェル
Atomでも、右クリックでGo to Declarationを選択でおk
Vimでもctagsとかでできる筈
■ クラス名を知る
Rails.logger.debug hoge.class
■ RSpec
ログを吐くようにする
spec/rails_helper.rb
のRSpec.configure do |config|
の前に
Rails.logger = Logger.new(STDOUT) ActiveRecord::Base.logger = Logger.new(STDOUT)
と書くと、アプリケーションログと実行したSQLを吐いてくれる (何故か自分の場合アプリケーションログがうまくだせなかった
■ set_trace_func
で発火したメソッドをトレースする
http://stackoverflow.com/questions/2219461/how-do-i-log-every-method-thats-called-in-a-ruby-program
log_file = File.open('/Users/your_name/Desktop/log.txt', 'w') set_trace_func proc { |event, file, line, id, binding, classname| log_file.printf("%8s %s:%-2d %10s %8s\n", event, file, line, id, classname) if event == 'call' unless file =~ /eval|vendor|rbenv|uploaders|initializers|support|db|rack/ # ログから外したい名前を並べておく }
メソッド名とクラスだけでいいならこんな感じで良いと思う↓
log_file = File.open('/Users/your_name/Desktop/hoge.txt', 'a') set_trace_func proc { |event, file, line, id, binding, classname| log_file.printf("%8s#%10s\n", classname, id) if event == 'call' unless file =~ /eval|vendor|rbenv|uploaders|initializers|support|db|rack/ # ログから外したい名前を適当に並べておく }
set_trace_func
は最後まで実行されるっぽいので、きりのいいところでraise "エラーメッセージ"
とでも書いて終了させましょう。
更に↑のhoge.txtをVimで編集していく。
下のコマンドは正規表現で要る/要らない言葉が含まれた行を削除するやつ。
" 削除 :%g/^.*<要らないクラス名とか>.*$/d " それ以外削除 :%v/^.*<見たいクラス名とか>.*$/d
■ Rails.logger.info "xxx"
ってやれ
コードにRails.logger.info "xxx"
のようにログ出力を埋め込んで、処理が実行されたタイミングやメソッドの戻り値、DBの値などを出力してみる
■ RSpec
失敗した時のlogs/test.log
を確認してみる
ログに出力された情報からテストが落ちた原因が推測できるかも
■ RSpec
DatabaseCleanerの設定をdeletion
からtruncation
にしてテストの度にDBを完全にリセットしてみる
DatabaseCleaner.strategy = :deletion => DatabaseCleaner.strategy = :truncation
■ pryのshow-source
でメソッドの定義を表示する
[1] pry(ClassName)> show-source connection.get From: /Users/your_name/Codes/hoge/vendor/bundle/ruby/2.3.0/gems/faraday-0.9.2/lib/faraday/connection.rb @ line 139: Owner: Faraday::Connection Visibility: public Number of lines: 6 def #{method}(url = nil, params = nil, headers = nil) run_request(:#{method}, url, nil, headers) { |request| request.params.update(params) if params yield(request) if block_given? } end