Sử dụng function try trong Rails

Trong quá trình làm việc với Rails, có nhiều hàm khá hữu ích, giúp code gọn gàng và dễ hiểu hơn nhưng chúng ta ít khi dùng đến, hôm nay mình xin giới thiệu cùng các bạn một hàm như thế, đó là hàm try().

Try là một hàm của Rails cho phép chúng ta gọi thử một hàm từ một object mà không cần lo rằng object đó đang có giá trị nil và sẽ gây ra exception. Sử dụng try() một cách hợp lý trong một số trường hợp là tốt, nhưng nếu lạm dụng try, chúng ta cũng có thể gặp phải một số vấn đề không mong muốn.

I. Sử dụng try khi kết quả trả về có thể có hoặc không Giả sử chúng ta có một cơ sở dữ liệu với quan hệ như sau: Chúng ta có model Product, một product có thể có hoặc không có Manufacture, chúng ta cần hiển thị tên nhà sản xuất của sản phẩm và đường link chỉnh sửa thông tin sản phẩm nếu người dùng là admin, theo cách thông thường chúng ta code như sau:

  <% unless @product.manufacturer.nil? %>
    <%= @product.manufacturer.name %>
  <% end %>

  <% if current_user && current_user.is_admin? %>
    <%= link_to 'Edit', edit_product_path(@product) %>
  <% end %>

Cách viết này đúng nhưng hơi dài dòng, nếu sử dụng hàm try() chúng ta có thể viết như sau:

 <%= @product.manufacturer.try(:name) %>

<% if current_user.try(:is_admin?) %>
  <%= link_to 'Edit', edit_product_path(@product) %>
<% end %>

Cách viết này rõ ràng là ngắn gọn, chuyên nghiệp và dễ hiểu hơn cách viết trên đúng không 😄.

II. Sử dụng try với tham số truyền vào và block

Bạn cũng có thể sử dụng try() với các hàm có tham số truyền vào hoặc block như sau: Với hàm có tham số: @product.manufacturer.try(:enough_in_stock?, 32)

 #Gọi hàm enough_in_stock và truyền tham số là 32, với các hàm nhiều tham số các bạn cũng truyền lần lượt vào như trên và ngăn cách bởi dấu phẩy.

Với block: @manufacturer.products.try(:map) { |p| p.name }

Lưu ý rằng số đối số trong block phải tương ứng với số đối số trong hàm try, nếu không, exception ArgumentError vẫn có thể xảy ra. Nếu gọi try với block mà không có đối số kèm theo thì block sẽ gọi đến đối tượng mà sử dụng hàm try đó. Ví dụ bên dưới, p trong block sẽ gọi đến đối tượngperson . person.try { |p| "#{p.first_name} #{p.last_name}" } Nếu person không có phương thức first_name hoặc last_name thì exception NoMethodError vẫn có thể xảy ra.

III. Sử dụng try liên tiếp nhau Cũng với ví dụ trên, giả sử mỗi nhà cung cấp có thế có tên hoặc không, chúng ta cũng có thể gọi 1 chuỗi các phương thức try() để lấy ra tên viết thường của các nhà cung cấp (nếu có) như sau: @product.try(:manufacturer).try(:factory_name).try(:downcase)

Cách viết trên trả về tên viết thường nhà máy của nhà phân phối (nếu có) và trả về nil nếu không có.

IV. Một số trường hợp không nên dùng try() Ta có dữ liệu trong một mối quan hệ một-nhiều như sau: một post có nhiều comments, và một post do 1 author tạo ra, khai báo trong Rails

class Post < ActiveRecord::Base
 has_many :comments
 belongs_to:author
end

class Comment < ActiveRecord::Base
 belongs_to :post
end

Khi muốn lấy ra tên tác giả bài viết từ một comment, ta có thể viết

@comment.post.author

Trong trường hợp logic đúng, kết quả trả về luôn luôn phải là tác giả của bài viết đó, nếu chúng ta nhận được 1 exception NoMethodError for nil class, điều đó có nghĩa dữ liệu của bạn không chính xác và đã có lỗi trong code của chúng ta khi tạo các bản ghi. Tuy nhiên một số dev sẽ sửa code như sau để tránh gây lỗi: @comment.try(:post).try(:author)

Lúc này kết quả trả về là nil, không có exception nào cả và sẽ gây khó khăn hơn để phát hiện ra lỗi và sửa lỗi, do đó cách viết trên với try không nên sử dụng .Chúng ta chỉ sử dụng try trong các trường hợp kết quả trả về có thể có hoặc không. Trong các trường hợp chắc chắn phải trả về kết quả như trên, chúng ta không nên sử dụng try vì sẽ làm sai logic hệ thống. Qua các ví dụ trên hi vọng các bạn đã hiểu rõ cách sử dụng hàm try, khi làm việc chúng ta hãy sử dụng hợp lý và không lạm dụng try() để rút gọn code và tránh các lỗi không đáng có.

Cảm ơn các bạn đã theo dõi bài viết.

Tham khảo: http://api.rubyonrails.org/classes/Object.html#method-i-try https://www.everydayrails.com/2011/04/28/rails-try-method.html


All Rights Reserved