Gọi AJAX trong Rails 5.1 sử dụng jQuery (hoặc không :))

Một phiên bản Rails không được đóng gói cùng jQuery được hiện thực hóa lần đầu tiên trong bản Rails 5.1. Trước kia, các phiên bản Rails vẫn thường phụ thuộc vào jQuery để có được chức năng Unobtrusive JavaScript nhưng bây giờ đã có thư viện rails-ujs riêng với vai trò tương tự.

Một trong những chức năng sử dụng phổ biến nhất của jQuery trong Rails là khả năng gọi AJAX thông qua form và link. Nếu lần đầu tiên sử dụng Rails 5.1, bạn có thể ngỡ ngàng trước cách gọi AJAX mới, đặc biệt với những thứ như data format hay CSRF token.

Vì vậy nên tôi viết bài hướng dẫn nhỏ này nhằm giới thiệu một số phương pháp gọi AJAX hiệu quả:

1. Sử dụng rails-ujs (không jQuery)

Một app Rails 5.1 thường được tự động tích hợp thư viện rails-ujs trong file application.js:

//= require rails-ujs

Nếu không muốn include cho chung cả app, mà chỉ muốn sử dụng ở một số nơi nhất định, ví dụ như trong trường hợp muốn build riêng phần frontend bằng React, ta có thể sử dụng rails-ujs bằng cách cài đặt như một package:

$ yarn add rails-ujs

Sau đó import và khởi động trong file JavaScript:

import Rails from 'rails-ujs'
Rails.start()

Tất nhiên là bỏ import tự động trong file application.js:

//= require rails-ujs

Ví dụ ta muốn gọi một AJAX POST đến một API đầu cuối với data có dạng:

mydata = {
 thing: {
  field1: value1,
  field2: value2,
}}

Việc gọi AJAX POST bằng rails-ujs trông giống hệt như gọi bằng jQuery:

Rails.ajax({
  type: "POST", 
  url: "/things",
  data: mydata,
  success: function(repsonse){...},
  error: function(repsonse){...}
})

Ngoại trừ một điều: ta không thể truyền data dưới dạng JSON. Mà ta cần phải convert data theo kiểu application/x-www-form-urlencoded, data sau khi convert có dạng:

mydata = 'thing[field1]=value1&thing[field2]=value2'

Bản thân jQuery cũng sử dụng chuẩn này để gọi AJAX, nhưng nó đã thực hiện ngầm bước này nên ta chỉ cần truyền JSON là có thể gọi được.

Hiện giờ tôi chưa tìm được đoạn doc nào nói về rails-ujs tự động thực hiện việc này, nếu có xin hãy góp ý ở mục comment, tôi sẽ update bài sớm nhất có thể.

rails-ujs tự động thêm CSRF token vào với request.

2. Sử dụng jQuery

Nếu việc convert data bằng tay khiến bạn nản trí, hoặc đơn giản là chưa quen với phương pháp mới, bạn vẫn có thể sử dụng jQuery như cũ. jQuery còn đảm nhận một số công việc khác trong app, vì vậy dưới đây tôi xin giới thiệu một số cách sử dụng jQuery trong Rails:

2.1. Sử dụng gem jquery-rails

Gem này được tích hợp tự động trong các phiên bản cũ của Rails. Bạn vẫn có thể cài đặt bằng cách thêm vào Gemfile:

gem 'jquery-rails'

Rồi chạy:

$ bundle install

Sau đó thêm jqueryjquery_ujs vào file application.js:

//= require jquery
//= require jquery_ujs

Đó là tất cả những gì cần làm. Bây giờ bạn có thể gọi AJAX như cũ:

$.ajax({
  type: "POST", 
  url: "/things",
  data: mydata,
  success: function(data, textStatus, jqXHR){...},
  error: function(jqXHR, textStatus, errorThrown){...}
})

jquery_ujs lo việc thêm CSRF token và convert data một cách tự động.

2.2. Sử dụng jQuery package từ npm

Nếu không muốn sử dụng phiên bản jQuery được đóng gói trong gem, ta có thể cài đặt jQuery như một package bằng npm:

$ yarn add jquery
$ yarn add jquery-ujs

Sau đó import vào file JavaScript:

import $ from ‘jquery’
import {} from ‘jquery-ujs’

Nhớ kiểm tra chắc chắn rằng bạn đã loại bỏ gem jquery-rails trong Gemfile và hai thư viện jqueryjquery_ujs trong application.js.

Nếu gặp báo lỗi không tìm thấy thư viện, trong webpack config ta thêm vào phần config.plugins:

new webpack.ProvidePlugin({
 $: “jquery”,
 jQuery: “jquery”
}),

Và ta có thể dùng jQuery để gọi AJAX như bình thường.

3.Sử dụng axios

axios là một thư viện dựa trên HTTP. Ta có thể sử dụng nó để tạo HTTP request từ node.js (trên server) và AJAX request từ brower.

Đây là một sự thay thế tốt nếu bạn không cần sử dụng các chức năng khác của jQuery. Để sử dụng axios trong app Rails 5.1, đầu tiên ta cần cài đặt:

$ yarn add axios

Sau đó import vào file JavaScript:

import axios from ‘axios’

Ta có thể gọi AJAX theo như thế này:

axios({
  method: 'POST', 
  url: '/things',
  data: mydata,
  headers: {
    'X-CSRF-Token': document.querySelector("meta[name=csrf-token]").content
  }
})
.then(function(response) {...},
.catch(function(error) {...}
})

Có một số điều cần lưu ý:

  • Ta phải tự thêm CSRF token vào header. Không giống như jquery_ujsrails-ujs, axios không tự động làm việc này.

  • Ta có thể cài đặt làm chế độ mặc định để tránh lặp lại nhiều lần trong code:

const csrfToken = document.querySelector("meta[name=csrf-token]").content
axios.defaults.headers.common[‘X-CSRF-Token’] = csrfToken
  • Ta có thể sử lý trường hợp gửi thành công và lỗi trả về trong hàm then.

Một phương pháp khác là sử dụng fetch, nhưng hiện tại API này vẫn đang được thử nghiệm và chưa hỗ trợ trên các trình duyệt. Vậy nên cách tốt nhất để sử dụng phương pháp này là sử dụng thư viện polyfill trên Github. Hiện tại các thông báo trả về đều cần được convert sang JSON trước khi sử dụng và việc sử lý lỗi khá rắc rối.

All Rights Reserved