Exception & StandardError trong Ruby
Trong công việc, đôi khi bạn phải bắt những lỗi như Exception & StandardError, hiểu rõ hơn về chúng sẽ giúp bạn quản lý công việc tốt hơn. Bình thường ta hay viết def some_method ##some code ... rescue Exception => e e.message end Exception đơn giản là 1 class ...
Trong công việc, đôi khi bạn phải bắt những lỗi như Exception & StandardError, hiểu rõ hơn về chúng sẽ giúp bạn quản lý công việc tốt hơn.
Bình thường ta hay viết
def some_method ##some code ... rescue Exception => e e.message end
Exception đơn giản là 1 class (http://ruby-doc.org/core-2.2.0/Exception.html) dùng để bắt những lỗi được raise hoặc fail trong 1 block begin end, Exception có những loại sau:
NoMemoryError ScriptError LoadError NotImplementedError SyntaxError SecurityError SignalException Interrupt StandardError -- default for rescue ArgumentError UncaughtThrowError EncodingError FiberError IOError EOFError IndexError KeyError StopIteration LocalJumpError NameError NoMethodError RangeError FloatDomainError RegexpError RuntimeError -- default for raise SystemCallError Errno::* ThreadError TypeError ZeroDivisionError SystemExit SystemStackError fatal – impossible to rescue
Như trong list trên StandardError cũng chỉ là một dạng Exception.
Exception bao gồm cả những lỗi như thiếu bộ nhớ (NoMemoryError), break khi đang thực hiện thao tác (SignalException::Interrupt), ví dụ ta dùng tổ hợp phím CTRL_C ...
StandardError bao gồm những lỗi phổ biến như chia cho 0 (ZeroDivisionError), không có hoặc gọi tên hàm sai (NameError::NoMethodError)...
Muốn raise 1 Exception với 1 message theo ý mình ta chỉ việc dùng (ví dụ với ZeroDivisionError):
raise ZeroDivisionError, "some error ..."
Muốn định nghĩa 1 dạng Error, ta chỉ việc thêm 1 class kế thừa (có thể là StandardError), sau đó raise như bình thường :
class SomeError < StandardError end def test_error agr raise SomeError, "some error ..." if agr.nil? end def test_another_error agr agr / 0 rescue ZeroDivisionError raise SomeError, "some error ..." end
Muốn xem full backtrace gọi method e.backtrace, hàm trả về dạng mảng các dòng báo lỗi.
Muốn thay đổi backtrace của error ta dùng method set_backtrace:
e.set_backtrace(["Hello", "World"]) e.backtrace Hello World
Method e.inspect để xem error đầy đủ.
Khi viết API, ta thường hay phải raise các error khi gặp các trường hợp đặc biệt và đưa ra endpoint những error_code dựa trên những dạng error mà chúng taraise ra.
Grape là 1 trong những gem giúp ta làm API khá, phổ biến.
Khi dùng Grape làm API ta thường raise những class lỗi tự định nghĩa bằng cách kế thừa class Grape::Exceptions::ValidationErrors rồi dùng rescue_from để catch lại.
Đối với những lỗi phát sinh trong quá trình sử lý ta cũng có thể dùng rescue_from để catch lại, đơn giản nhất là rescue_from :all do |e|, tuy nhiên chỉ có tác dụng đối với StandardError và không đối với Exception.
Grape::Exceptions::ValidationErrors có base là StandardError do vậy rescue_from sẽ bắt được hết error tự định nghĩa do kế thừa nó.
Trong Grape::Exceptions::ValidationErrors ta có message, headers hoạt động như các attributes để ta có thể gán thông tin tiện cho việc xử lý lúc catch lại.
def validate_param! attr_name, params raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], headers: Settings.api_validation.bad_digit_params unless params[attr_name].try(:length).try :<=, @option end ... rescue_from Grape::Exceptions::ValidationErrors do |e| missing_params = bad_format_params = bad_digit_params = [] e.each do |_param, errors| if errors[:headers] == Settings.api_validation.bad_digit_params bad_digit_params += errors[:params] end end end
Cảm ơn và hi vọng bài viết giúp ích trong công việc của bạn.