Sử dụng Ajax/JavaScript với Rails

1 Giới thiệu về Ajax

Đầu tiên chúng ta sẽ tìm hiểu hoạt động của trình duyệt (browser) như thế nào khi chúng ta vào một trang web bất kì. Khi bạn gõ địa chỉ trang web vào thanh địa chỉ vào thanh địa chỉ của browser và ấn phím enter lúc đó browser sẽ tạo một yêu cầu (request) tới server. Kết quả mà browser nhận được từ server đơn giản là một đoạn text chứa nội dung của trang web mà bạn muốn đến. Browser sẽ phân tích kết quả này dựa vào đó để gửi tiếp các request tiếp theo lên server để lấy các files liên quan khác nhưng JavaScript files, stylesheets hay file ảnh. Sau khi quá trình đó hoàn tất thì bạn sẽ nhìn thấy browser hiện thị một trang web không chỉ đơn thuần là những dòng văn bản mà có thêm các hiệu ứng từ JavaScript và có một giao diện đẹp mắt từ stylesheets. Nếu bạn click vào bất cứ một đường link nào trên trang này browser sẽ tạo một request khác tới một trang web khác quá trình tải trang web này lại bắt đầu như trên tạo thành một chu trình gửi yêu cầu và nhận kết quả trên browser (request response cycle).

Đôi khi ta tạo một số request để thay đổi một nội dung rất nhỏ trên một trang ví dụ như comment vào một status chẳng hạn. Việc sau mỗi lần comment thì trang lại tạo một request và load lại toàn bộ trang là không tốt khiến người dùng phải chờ đợi khá lâu trong khi nội dung của trang web chỉ thay đổi một chút. Để đáp ứng được yêu cầu trên người ta dùng Ajax. Vậy Ajax là gì?

Ajax (Asynchronous JavaScript and XML) là một kĩ thuật sử dụng JavaScript trên browser để tạo các tương tác ngầm gửi/nhận thông tin với, trong quá trình JavaScript gửi request tới server thì không làm thay đổi bất cứ điều gì trên trang web. Sau khi nhận được được kết quả trả về của server thì tùy vào kết quả trả về mà ta dùng JavaScript để thay đổi nội dung của trang tương ứng với kết quả đó. Thường những request bằng Ajax là những request nhỏ và dữ liệu trả về từ server cũng rất nhỏ, browser cũng không phải load lại những files stylesheets và Javascript nên tốc độ của Ajax thực sự rất nhanh. Do đó việc sử dụng Ajax làm cho trang web của bạn thân thiện hơn phản hồi nhanh với những tương tác của người dùng.

Việc sử dụng CoffeeScript cũng khá là phổ biến nên các ví dụ sau tôi sẽ dùng CoffeeScript. Các bạn cũng có thể chuyển đoạn mã Coffee này sang Javascript tại địa chỉ sau Change CoffeeScript to JS.

2. Ajax đơn giản

Khi sử dụng Ajax thuần thì Rails cũng giống với tất cả các trang bình thường, ta chỉ cần nhúng đoạn mã JavaScript có sử dụng Ajax và trang web là chúng có thể chạy. Dưới đây là một ví dụ đơn giản dùng Ajax gửi một request với method get lên server.

 $.ajax(url: "/test").done (html) ->
  $("#results").append html

Trong đoạn mã này sẽ dùng một Ajax gửi một request lên server tại địa chỉ your_host/test với http method mặc định của ajax method là get. Sau khi nhận được kết quả trả về từ server là html, ta sẽ thêm đoạn html và trong thẻ có id là results. Để hiểu thêm về jQuery ajax method bạn có thể tham khảo chi tiết tại jQuery ajax method

Tuy nhiên việc dùng method ajax của jQuery khá dài và khó biết được method hiện tại đang dùng là gì. jQuery cũng cung cấp một số method nhưng get, post ... Theo ví dụ trên ta chó thể thay thế bằng jQuery get method như sau

 $.get("/test").done (html) ->
  $("#results").append html

jQuery còn cung cấp rất nhiều method hữu ích khác, bạn có thể tham khảo chi tiết tại địa chỉ sau jQuery AJAX Methods

3. Rails Ajax helpers

Rails Ajax helpers gồm có 2 phần một nửa là JavaScript và nửa còn lại là Ruby view helpers. Ruby view helper sẽ tạo ra các thẻ và các thuộc tính của thẻ này. Nhiệm vụ của Javascript rails.js sẽ đọc các thuộc tính trong từng thẻ và nhúng các sự kiện (attack event) vào các Object có thuộc tính phù hợp. Thông thường ta chỉ cần thêm thuộc tính data-remote="true" vào trong các DOM object khi render trang là các object này sẽ gửi nhận dữ liệu bằng Ajax thay thế cho các action mặc định của chúng.

Dưới đây tôi sẽ lấy một ví dụ với form_for tương tự với các helper khác như form_tag, link_to hay button_to bạn cũng chỉ cần thêm tùy chọn remote có giá trị là true vào là được.

<%= form_for(@article, remote: true) do |f| %>
  ...
<% end %>

HTML tương ứng với đoạn code trên như sau

<form accept-charset="UTF-8" action="/articles" class="new_article" data-remote="true" id="new_article" method="post">
  ...
</form>

Bạn có thể thấy với tùy chọn remote: true sau khi render ra HTML ta sẽ có thuộc tính data-remote với giá trị là true. Bây giờ form này khi submit sẽ dùng Ajax chứ không phải là browser submit.

Bạn cũng có thể bắt sự kiện kết quả của ajax request trả về khi ta submit form này bằng cách sau.

$(document).ready ->
  $("#new_article").on("ajax:success", (e, data, status, xhr) ->
    $("#new_article").append xhr.responseText
  ).on "ajax:error", (e, xhr, status, error) ->
    $("#new_article").append "<p>ERROR</p>"

Trong ví dụ ở trên tôi đã sử dụng 2 event là ajax:success khi kết quả trả về thành công và ajax:error khi ajax request gặp lỗi. Bạn có thể tham khảo thêm các event khác tại Ajax events.

4. Rails Turbolinks

Các ứng dụng Rails thường sử dụng Turbolinks để tăng hiệu năng của trang web. Vậy Turbolinks là gì và Turbolinks có tác dụng như thế nào?

Tư tưởng củ Turbolinks cũng khá đơn giản là Turbolinks thêm một sự kiện (event) click cho tất cả các thẻ a trên trang. Nếu browser hỗ trợ PushState, khi bạn click vào thẻ bất kì trên trang thay vì redirect tới một trang khác thì Turbolinks sẽ tạo một Ajax request, sau khi nhận được kết quả trả về sẽ thay thế toàn bộ nội dung của thẻ body bằng nội dung của thẻ body trong kết quả trả về. Do việc không phải load lại các Javascript trên thẻ head nên trang web sử dụng Turbolinks hoạt động khá nhanh.

Để sử dụng Turbolinks trong Rails cũng khá đơn giản bạn chỉ cần thêm vào trong Gemfile dòng sau

gem 'turbolinks'

và thêm vào file application.js như sau

//= require turbolinks

Như vậy bạn đã hoàn thành việc sử dụng Turbolinks cho trang web của mình.

Trong trường hợp bạn muốn disable Turbolinks bạn chỉ cần thêm thuộc tính data-no-turbolink vào trong các thẻ mà bạn không muốn sử dụng Turbolinks. Ví dụ

<a href="..." data-no-turbolink>Không sử dụng Turbolinks</a>.

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