Debugging Rails 遇到Bug別慌!先看懂錯誤訊息!

在新手學習Ruby & Rails時,可能完全不知道error或exception要如何處理,一跳出錯誤訊息就傻掉了,但大多的情況都可以從錯誤訊息中判斷出問題所在,省下Google或發問的時間。

在這邊簡單說明如何閱讀錯誤訊息:

1. 看懂Ruby irb當中的錯誤訊息

學習Ruby最開始都是在console的IRB(Interactive Ruby)當中(除非你跳過這個階段)。在IRB當中,錯誤訊息顯示方式非常直接、原始。以下是一個很典型的錯誤:

簡單將這個訊息分為幾個部分:

(1) 標題:NoMethodError

Ruby中有非常多error及exception的類型,分別代表不同的錯誤。例如NoMethodError代表使用者試圖呼叫一個不存在的method,通常是打錯字造成誤判或是根本就還沒宣告。

詳細的列表可以從下方的延伸閱讀中找到。

(2) 內容:undefined method `merge' for [1, 2, 3]:Array

這段訊息較長,但基本上就是標題的延伸,指出哪個地方有問題。以這個錯誤為例,他指出使用者要在[1,2,3]使用merge這個method,但一個數列(Array)並沒有merge這個method,他好心告訴我們應該要先宣告以後才能使用。

(3) 來源:from (irb):3

這串來源告訴我們是在哪個檔案、哪一行出了問題,叫做stack trace,目前程式很小,只有2行,如果程式很大,stack trace列表會非常長。由於我們是在irb當中,因此他首先秀出irb這個位址,並告訴我們是在第3行的地方產生這個錯誤。

下方會列出其他的檔案,告訴我們這整串的程式運作過程。由於整個Ruby程式是連動的,所以一個複雜的程式會牽動很多檔案,從這裡我們就可以看出每一個檔案在哪個環節出了問題。例如在這裡,我們irb的檔案是存在bin這個資料夾內,他就把檔案位置給我們看,並說明是在main區塊內。

from /Users/hsiehadler/.rvm/rubies/ruby-2.1.2/bin/irb:11:in 'main'

什麼是main區塊?代表他不屬於任何一個class,如果我們是在class內產生的錯誤例如:

class Post
    def draft
        Draft.create(@post)
    end
end

如果這個method有產生什麼錯誤,他會在最後標註class: Post代表是在Post這個class當中產生的錯誤。

(4) 看懂了就來debug

總和來說,以上的例子我們宣告了ab為數列(Array),但數列並沒有包含merge這個method,所以出現了錯誤訊息,告知我們在Array這個class當中並沒有merge這個用法,可以改為使用.push。

2. 看懂Rails Expection頁面

在Rails當中,錯誤的呈現方法相同,但包裝得比較漂亮一點,比較能看出構造來。以下是一個很典型的Rails錯誤畫面:

分類說明:

(1) 標題

比起irb當中的標題,這裡的標題構造要稍微複雜一些,我們可以分成兩個部分:

ActiveRecord::RecordNotFound in PostsController#show

前面的部分一樣是錯誤類別,而ActiveRecord是Rails使用的資料庫框架,底下引發了RecordNotFound這個錯誤,告訴我們無法找到相對應的資料。

後面的部份點出是在哪一個部分造成的錯誤,記得Rails的MVC架構,就可以看懂這裡是在post controller裡面的show action造成的錯誤。

(2) 內容: Couldn't find Post without an ID

這告訴我們詳細的錯誤內容,可以看出由於find這個method是搜尋資料庫內的id,所以一定是要使用數字帶入查詢。他告訴我們:『你不給我id是要找什麼鬼?』

(3) 來源:@post = Post.find(params[:post_id])

同樣的,這邊點出主要錯誤的範圍、行數、前後文為何。

(4) 來源: stack trace

這邊有三種trace可選,進階的開發者可以選擇full trace來看整體rails架構以及運算的邏輯。入門開發者只要觀看預設的application trace就夠了,只會顯示我們自己操作的內容。

(5) 參數: {"id"=>"1"}

Request這個部分會顯示我們傳送給伺服器的參數。

(6) 看懂了就來debug

這邊可以看出我們傳送了參數{ "id" => "1"}給伺服器,要求回傳一個單獨的post內容,但很明顯的在show action中有一個錯誤,將搜尋用的find method後方參數誤打成params[:postid]。我們在request中並沒有回傳任何postid變數,造成Rails無法用任何值去搜尋資料庫,也導致最後找不到任何資料。

只要將post_id改為id,就可以解決這個問題了。

在了解要如何閱讀錯誤訊息後,下一步就可以來看看有哪些常見的錯誤類型,以及最有可能發生的原因。

延伸閱讀

Ruby Exceptions Reference