Debugging Rails 沒有錯誤訊息卻還是有bug!要如何即時除錯?


pry

大家應該都遇過這個情形,給了一個method,沒有錯誤訊息,出來的結果卻是錯的!

遇到這樣的情況,要如何判斷是哪裡錯呢?一個一個試嗎?

你需要pry當朋友

強大的即時debugger工具:pry,他就像rails 內建的debugger一樣,擁有強大的除錯功能,但更花俏,也更實在。有以下特點:

  1. 排版比起一般的rails console易讀
  2. 可選擇不同的操控邏輯
  3. 即時攔截,debug當下的variable、method
  4. 提供step、next等逐行debug功能

安裝與執行Pry

安裝pry非常簡單,在Gemfile中加入:

gem 'pry'
gem 'pry-rails'
gem 'pry-nav'

接著在console中輸入bundle就完成了。

pry有非常多外掛,包括pry-byebug, pry-nav等一大堆外掛,但隨著版本進步,很多特色都直接放入pry當中了,在這邊介紹幾個比較有特色的。

載入環境

一般來說,直接在console當中輸入pry,就會進入irb環境,而在rails專案資料夾底下輸入pry預設並不會載入rails環境,因此需要在執行pry時必須同時執行以下指令:

$ pry -r ./config/environment

這樣就像直接輸入rails console指令一樣,可以讀取專案內的內容。

如果你有安裝pry-rails這個gem,就只要執行:

$ rails c

就可以切換至pry並載入rails環境了。

攔截rails執行內容

這是本篇最大的重點,pry提供的debug功能讓開發者可以在程式間插入一段用法:

def index
    binding.pry
end 

只要程式執行時,遇到那段binding.pry,就會自動在console當中進入debug模式,如下圖:

]

畫面上會出現一個console可以使用,這有什麼特別的?重點在於,通常我們需要攔截除錯的時候,都是因為有些variable和method回傳的內容不符期待,才會有這樣的問題。在這個pry console當中,我們可以直接觀看變數的情況,並立刻進行實驗、修正。

Pry使用重點

pry console比起一般rails console可以下的指令更為精確。

cd

啥?cd是啥?

意思是可以直接進入某個變數或class當中操作,例如:

我們可以利用這個階層的觀念,一層一層進入物件或變數當中檢查。

self

檢查目前在哪個scope當中,並且自己有什麼樣的variable或symbol。

ls、methods

這兩個指令可以看到現在的這個class或scope內有什麼樣的variable或method可以使用。

當然,列出來的指令一定非常多,我建議使用methods指令時,看最上面的指令即可,因為那些才是我們自訂的指令。或是可以利用include來看我們想要查看的method存不存在。

> self.include? :new

有的話,我們就可以實際在pry中執行並帶入參數看看結果為何。

next、step

這兩個可說是debug神器,因為在較複雜的method當中,我們會需要一行一行的檢視,看variable和其他method計算的結果到底是在哪個點出錯的。

step意思是請pry執行這一行,並在下一行停止。
next意思是請pry執行這一段block,並在下一段block開始時停止。

這兩個方法大同小異,但next所跨越的範圍稍微大一點點,因為會把一小段code執行完畢,而step是真的要逐行檢視的時候使用。而這兩個方法都會跨越到rails的source code裡面,算是超級精密的檢視。

continue

如果是初學者,可能不需要這麼精細的step和next檢視。建議在幾個關鍵的地方綁上binding.pry,接著在一個地方檢視完畢以後,使用continue指令,程式就會繼續執行,到下一個binding.pry的地方才會停止。

此外,有些gem將這些特色全部合在一起,變成只要裝1~2個gem即可,例如pry-byebug或pry_debug等等,可以參考這些說明文件看有何不同(基本上大同小異)。由於pry功能真的很豐富,我也還沒有全部嘗試過,在延伸閱讀當中有更多資料可以查看。

exit-all

直接跳出pry除錯,繼續執行程式。

在瀏覽器中直接debug

另一種作法是使用先前介紹的better_errors,可以直接在瀏覽器畫面中debug。

作法是在覺得有問題的地方加上raise,rails會在該行指令處產生一個RuntimeError,就會進入錯誤畫面了。例如:

def index
    @post = Post.all
    raise
end 

如果不喜歡在console中debug,這也是一個好方法,但個人認為較pry的功能不完全,且指令打多了畫面會很亂。若是要進行比較陽春的除錯,就可以考慮用這個方法。

延伸閱讀

Rails除錯指南

Pry官網

xdite部落格

RailsCast

CC授權圖片:pixabay