Cách sử dụng ActiveSupport::ActionableError trong Rails 6

Khi làm việc trong một team sử dụng Rails, chúng ta thường gặp phải lỗi PendingMigrationError mỗi lần bạn nào đó thêm migration hoặc gặp phải các lỗi khác cần chạy lệnh rails, rake task, v.v. Mỗi lần như thế bạn lại phải ngồi thực hiện một mớ thao tác 😄

Rails đã có thêm một cách giải quyết vấn đề này trên ngay trên cái trang bắt ra thông báo lỗi đó 💯

Rails 6 đã được bôt xung module ActiveSupport::ActionableError để xác định các hành động mà chúng ta muốn thực hiện ngay trên trang thông báo lỗi.

Ví dụ, nếu chạy thiếu migration thì Rails 6 sẽ báo lỗi như sau:

Mặc định, Rails thêm một button "Run pending migrations" trên trang này. Khi nhấn vào button này, rails sẽ chay rails db:migrate. Trang sẽ reload sau khi thực thì xong.

Chúng ta có thể tùy biến thêm các hành động để thực thì khi xảy ra một exception nào đó 😍

Áp dụng vào thực tế

Chúng ta cần include module ActiveSupport::ActionableError vào trong error class. Bạn có thể monkey patch vào một error class có sẵn hoặc đinh nghĩa một class mới.

Class method #action dùng để định nghĩa hành động khi xảy ra lỗi. Đối số đầu tiên của #action là tên của action đó. Giá trị này chính là chuỗi sẽ được hiển thị ở button trên trang báo lỗi. Phần block truyền cho #action là nơi chúng ta viết các lệnh hoặc code để sửa lỗi gặp phải.

Cùng tạo một ví dụ seed dữ liệu cho bảng posts nếu chưa có bản ghi nào khi truy cập vào PostsController.

# app/controllers/posts_controller.rb

class PostsController < ApplicationController

  def index
    @posts = Post.all
    if @posts.empty?
      raise PostsMissingError
    end
  end
 
end
# app/errors/posts_missing_error.rb

class PostsMissingError < StandardError

  include ActiveSupport::ActionableError

  action "seed posts data" do
    Rails::Command.invoke 'posts:seed'
  end

end
# lib/tasks/posts.rake

namespace :posts do

  desc 'posts seed task'
  task :seed do
    Post.create(title: 'First Post')
  end

end
# app/views/posts/index.html.erb

<% @posts.each do |post| %>
  <%= post.title %>
<% end %>

Khi truy cập vào /posts (posts#index action) khi chưa có post nào. Chúng ta sẽ thấy trang báo lỗi như sau kèm với cái button như hình.

Khi chọn seed posts data rails sẽ thực hiện rake task và tự động reload lại /posts /

ActionDispatch::ActionableExceptions middleware có nhiệm vụ thực thi các action từ trang báo lỗi. ActionableExceptions middleware dispatches action từ ActionableError và chuyển hướng khi block mà ta đã truyền vào action đã được thực thi xong. Template của cái button này thì nằm ở đây nè.

Nguồn: https://blog.bigbinary.com/2019/10/01/rails-6-adds-active-support-actionable-error.html