Trả về html template cho request format bất kì trong Rails với Rambulance gem

Rambulance gem Rambulance là một gem đơn giản, gọn nhẹ, kế thừa từ ActionController::Base, được dùng trong việc hiển thị các trang lỗi cho ứng dụng Rails của bạn Về cách cài đặt và sử dụng, các bạn có thể tham khảo Github yuki24/rambulance Nói sơ qua thì các cặp ngoại lệ – trạng thái

Rambulance gem

Rambulance là một gem đơn giản, gọn nhẹ, kế thừa từ ActionController::Base, được dùng trong việc hiển thị các trang lỗi cho ứng dụng Rails của bạn
Về cách cài đặt và sử dụng, các bạn có thể tham khảo Github yuki24/rambulance
Nói sơ qua thì các cặp ngoại lệ – trạng thái được định nghĩa trong file config/initializers/rambulance.rb theo cú pháp như sau:

# config/initializers/rambulance.rb
config.rescue_responses = {
  "ActiveRecord::RecordNotUnique" => :unprocessable_entity,
  "CanCan::AccessDenied"          => :forbidden,
  "YourCustomException"           => :not_found
}

Các template của trang lỗi được viết trong views (thường được viết trong views/errors. Ví dụ: app/views/errors/not_found.html.erb hoặc app/views/errors/not_found.json.jbuilder. Và dựa vào định dạng của request mà trả về template json hay html (hoặc loại khác)

Vấn đề: Làm thế nào để trả về trang lỗi html cho các request như css, pdf

Trước khi đi vào cách giải quyết, mình sẽ nói về lỗi sẽ xảy ra. Ở đây mình sẽ tạo một ứng dụng mới hoàn toàn và không thêm bất cứ resource nào

  • Trước hết, khi chưa thêm gem Rambulance vào và truy cập localhost:3000/abc, trang lỗi của rails sẽ hiển thị ra:

image.png

Sau khi thêm Rambulance vào (ở đây mình đã sửa template một chút. các bạn có thể sử dụng template mặc định của Rambulance)

image.png

image.png

-> Các trang lỗi sẽ được hiển thị ra theo đúng định dạng của request là json hay html (trường hợp không có đuôi thì mặc định giống html)

Tuy nhiên khi gửi request css thì sao?

image.png

-> Vẫn là lỗi 404, nhưng lỗi hiện thị đã khác

Ở đây có 2 nguyên nhân:

  • Nguyên nhân 1: Không có template app/views/errors/not_found.css.*
    – Trường hợp này chúng ta không thể giải quyết bằng thêm template được. Lý do là chúng ta đang muốn hiển thị mỗi trang lỗi theo định dạng html
  • Nguyên nhân 2: Cùng xem log nhé

ActionController::RoutingError (No route matches [GET] “/abc.css”):

actionpack (6.0.4.6) lib/action_dispatch/middleware/debug_exceptions.rb:36:in call' web-console (4.2.0) lib/web_console/middleware.rb:132:incall_app’
web-console (4.2.0) lib/web_console/middleware.rb:28:in block in call' web-console (4.2.0) lib/web_console/middleware.rb:17:incatch’
web-console (4.2.0) lib/web_console/middleware.rb:17:in call' actionpack (6.0.4.6) lib/action_dispatch/middleware/show_exceptions.rb:33:incall’
railties (6.0.4.6) lib/rails/rack/logger.rb:37:in call_app' railties (6.0.4.6) lib/rails/rack/logger.rb:26:inblock in call’
activesupport (6.0.4.6) lib/active_support/tagged_logging.rb:80:in block in tagged' activesupport (6.0.4.6) lib/active_support/tagged_logging.rb:28:intagged’
activesupport (6.0.4.6) lib/active_support/tagged_logging.rb:80:in tagged' railties (6.0.4.6) lib/rails/rack/logger.rb:26:incall’
sprockets-rails (3.4.2) lib/sprockets/rails/quiet_assets.rb:13:in call' actionpack (6.0.4.6) lib/action_dispatch/middleware/remote_ip.rb:81:incall’
actionpack (6.0.4.6) lib/action_dispatch/middleware/request_id.rb:27:in call' rack (2.2.3) lib/rack/method_override.rb:24:incall’
rack (2.2.3) lib/rack/runtime.rb:22:in call' activesupport (6.0.4.6) lib/active_support/cache/strategy/local_cache_middleware.rb:29:incall’
actionpack (6.0.4.6) lib/action_dispatch/middleware/executor.rb:14:in call' actionpack (6.0.4.6) lib/action_dispatch/middleware/static.rb:126:incall’
rack (2.2.3) lib/rack/sendfile.rb:110:in call' actionpack (6.0.4.6) lib/action_dispatch/middleware/host_authorization.rb:103:incall’
webpacker (4.3.0) lib/webpacker/dev_server_proxy.rb:23:in perform_request' rack-proxy (0.7.2) lib/rack/proxy.rb:67:incall’
railties (6.0.4.6) lib/rails/engine.rb:527:in call' puma (4.3.11) lib/puma/configuration.rb:228:incall’
puma (4.3.11) lib/puma/server.rb:718:in handle_request' puma (4.3.11) lib/puma/server.rb:472:inprocess_client’
puma (4.3.11) lib/puma/server.rb:328:in block in run' puma (4.3.11) lib/puma/thread_pool.rb:134:inblock in spawn_thread’
Processing by Rambulance::ExceptionsApp#not_found as CSS
Rendering vendor/bundle/ruby/3.0.0/gems/rambulance-2.2.0/app/views/errors/internal_server_error.text.erb
Rendered vendor/bundle/ruby/3.0.0/gems/rambulance-2.2.0/app/views/errors/internal_server_error.text.erb (Duration: 5.7ms | Allocations: 419)
Completed 404 Not Found in 16ms (Views: 12.1ms | ActiveRecord: 0.0ms | Allocations: 4672)

  • Đầu tiên là ActionController::RoutingError (No route matches [GET] "/abc.css"):
    • Dễ hiểu vì route này chưa được định nghĩa, tạo ra ngoại lệ RoutingError. Ngoại lệ này tương ứng với template not_found của Rambulance
  • Tuy nhiên nhòn ở dưới cùng, template được render ra lại là internal_server_error
    -> Vậy lý do là gì?

Nhìn vào request dễ nhận thấy, format của request này là text/css. Trong khi không tìm thấy template nào cho css dẫn đến một lỗi khác, và lỗi này được gọi ra trong vendor
-> cần làm sao để hiện thị ra đúng lỗi 404

Giải pháp

Ở đây mình tạo ra một method mới trong ApplicationController có tên routing_error để raise lên lỗi của Rambulance như sau

Rails.application.routes.draw do# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  match '*not_found_path', to:'application#routing_error', via::allend
classApplicationController<ActionController::Basedefrouting_errorraiseActionController::RoutingError,"No route matches"endend

Như vậy, với bất kì request nào không khớp với các path được định nghĩa trong route sẽ gọi đến method routing_error
Tuy nhiên đến đây vẫn chưa xong. Các request css vẫn xảy ra lỗi như trên. Vì vậy cần định nghĩa sao cho:
– Các request json trả về json
– Các request không phải json sẽ trả về html
Điều này giải quyết bằng cách thêm cài đặt format cho route, và mình sửa như sau:

Rails.application.routes.draw do# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  match '*not_found_path', to:'application#routing_error', constraints: lambda {|req| req.format = req.format ==:json?:json::html}, via::allend

Và kết quả:
image.png

Ngoài ra thì các request như pdf, js, v.v… cũng có kết quả tương tự

Phương pháp này được áp dụng trong bài toán: Hiển thị trang 404 cho các đường dẫn không tồn lại thay vì trang 500

Tái bút

Bài viết này được viết bởi một thành viên chưa có nhiều kinh nghiệm về Rails, cũng như chưa tìm hiểu kỹ nên sẽ có những lý giải sai, cách trình bày chưa rõ ràng, và các giải quyết cũng chưa phải tối ưu. Rất mong các anh chị và các bạn có thể góp ý, đưa ra nhận xét cũng như các cách giải quyết hay hơn để bản thân em/mình có thể học hỏi được thêm. Cảm ơn mọi người đã ghé thăm bài viết!

Nguồn: viblo.asia

Bài viết liên quan

Sự Khác Nhau Giữa Domain và Hosting Là Gì?

Sự khác nhau giữa domain và hosting là gì? Bài này giải thích ngắn và dễ hiểu nh

Shared Hosting hay VPS Hosting: Lựa chọn nào dành cho bạn?

Bài viết giải thích rõ shared hosting và vps hosting là gì và hướng dẫn chọn lựa

Thay đổi Package Name của Android Studio dể dàng với plugin APR

Nếu bạn đang gặp khó khăn hoặc bế tắc trong việc thay đổi package name trong And

Lỗi không Update Meta_Value Khi thay thế hình ảnh cũ bằng hình ảnh mới trong WordPress

Mã dưới đây hoạt động tốt có 1 lỗi không update được postmeta ” meta_key=