12/08/2018, 16:31

Những ngoại lệ phổ biến trong Ruby on Rails

Trong khi làm việc với Ruby, chúng ta rất hay gặp phải các thông báo lỗi về Exception, sau đây là sơ đồ phân cấp các Exception trong Ruby với class Exception là gốc chính: Exception NoMemoryError ScriptError LoadError NotImplementedError SyntaxError SignalException Interrupt ...

Trong khi làm việc với Ruby, chúng ta rất hay gặp phải các thông báo lỗi về Exception, sau đây là sơ đồ phân cấp các Exception trong Ruby với class Exception là gốc chính:

Exception
 NoMemoryError
 ScriptError
   LoadError
   NotImplementedError
   SyntaxError
 SignalException
   Interrupt
 StandardError
   ArgumentError
   IOError
     EOFError
   IndexError
   LocalJumpError
   NameError
     NoMethodError
   RangeError
     FloatDomainError
   RegexpError
   RuntimeError
   SecurityError
   SystemCallError
   SystemStackError
   ThreadError
   TypeError
   ZeroDivisionError
 SystemExit

Trong đó ta có thể thấy được rằng StandardError là một superclass với nhiều class con chứa các lỗi phổ biến nhất mà chúng ta thường gặp, sau đây chúng ta sẽ cùng tìm hiểu về các lỗi ấy.

NoMethodError

undefined method `grade' for nil:NilClass
undefined method `<<' for {}:Hash

Khi một phương thức được gọi cho 1 đối tượng cụ thể không tồn tại thì lỗi này được trả về, phổ biến nhất là nil:Nilclass

[1] pry(main)> nil.grade
NoMethodError: undefined method `grade' for nil:NilClass
[2] pry(main)>

Nếu không có yêu cầu đặc biệt cho việc xử lý kết quả (ví dụ như chỉ dùng kết quả để show) thì bạn hãy sử dụng try để tránh lỗi này:

[2] pry(main)> nil.try(:something)
=> nil
[3] pry(main)>

NameError

undefined local variable or method `grade' for #
uninitialized constant Report 

Lỗi trên xảy ra khi 1 biến không được khởi tạo, cách sửa lỗi này đó là gán giá trị khởi tạo cho nó.

NoMethodError(cho private method)

[6] pry(main)> u.password_complexity
NoMethodError: private method `password_complexity' called for #<User:0x00000016063680>

Lỗi này ta có thể gặp khi truy cập trực tiếp một private object method từ một object. Ta có thể tránh việc này bằng cách chuyển method sang public hoặc dùng send:

[7] pry(main)> u.send(:password_complexity)
=> nil
[8] pry(main)>

ActiveRecord::RecordNotFound

[8] pry(main)> User.find 10000
  User Load (0.5ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 10000 LIMIT 1
ActiveRecord::RecordNotFound: Couldn't find User with 'id'=10000

Lỗi xảy ra khi ra muốn truy xuất một bản ghi có id không tồn tại trong DB bằng find chảng hạn.Để tránh lỗi này chúng ta có thể sử dụng find_by hoặc where:

[2] pry(main)> User.find_by_id(params[:id]) 
=> nil
[3] pry(main)> User.find_by(id: params[:id])
=> nil
[4] pry(main)> User.where(id: params[:id]).first
=> nil

TypeError

[9] pry(main)> "1" + 2
TypeError: no implicit conversion of Fixnum into String

Khi cộng một String và 1 số Integer thì sẽ phát sinh lỗi này, lỗi này có thể xuất hiện khi ta thực hiện thao tác với nhiều loại khác nhau như String, FixNum, Array, Hash, Float, để tránh lỗi này thì ta nên convert các object về cùng 1 kiểu:

[3] pry(main)> "1" + 2
TypeError: no implicit conversion of Fixnum into String
from (pry):3:in `+'
[4] pry(main)> "1".to_i + 2
=> 3
[5] pry(main)>

ArgumentError

wrong number of arguments (0 for 1)

Lỗi này xảy ra khi ta gọi hàm mà truyền vào số lượng tham số không chính xác như khi định nghĩa hàm, chảng hạn:

my_grade = student(college, grade)

def student(college) # Argument error
end

def student(college, grade = 0) # works fine as grade is assigned 0.
end

Truyền đúng số lượng tham số hoặc xét giá trị mặc định cho những tham số có thể không nhất thiết cần truyền khi gọi hàm là cách giải quyết lỗi này.

0