มาทำความเข้าใจว่าทำไม AJAX จึงมีอยู่ เพื่อให้คุณได้ไอเดียที่ดีขึ้นว่าจะใช้มันในโปรเจกต์ Rails ของคุณอย่างไร
เมื่อคุณเข้าชมเว็บไซต์ จะเกิดอะไรขึ้น?
หน้าเว็บถูกโหลดจากเซิร์ฟเวอร์ แต่ถ้าคุณต้องการดูข้อมูลใหม่ คุณต้องโหลดหน้าใหม่เพื่ออัปเดต หรือคลิกลิงก์ไปหน้าอื่น
นี่คือ ขั้นตอนแบบซิงโครนัส (synchronous flow)
ข้อมูลใหม่จะถูกนำเสนอ רק เมื่อมีการขอหน้าใหม่จากเซิร์ฟเวอร์
แต...
ถ้าคุณ ไม่อยากให้โหลดหน้าใหม่ ล่ะ?
ถ้าคุณต้องการ ดึงข้อมูลจากแบ็กเอนด์ เมื่อไหร่ก็ได้ เพื่อที่จะอัปเดตส่วนใดส่วนหนึ่งของหน้าปัจจุบัน?
นี่คือที่มาของ AJAX
AJAX ย่อมาจาก Asynchronous JavaScript & XML
มันคือเทคนิคที่เป็นอิสระจากเฟรมเวิร์กเว็บของคุณ แต่ Rails โดยเฉพาะมีการสนับสนุนที่ดีมาก ตามที่คุณจะได้เรียนรู้ในบทความนี้
โปรดจำไว้ว่าการเพิ่ม AJAX ลงในแอปทำให้มันซับซ้อนขึ้น
คำขอ AJAX โดยตรง
AJAX มี 2 ส่วน: คำขอ (request) ซึ่งคุณสร้างจากเบราว์เซอร์โดยใช้ JavaScript และการตอบสนอง (response) ซึ่งคุณจัดการจากแอป Ruby ของคุณ
คุณสามารถ สร้างคำขอ AJAX ด้วย JavaScript ธรรมดาได้
แต่มันต้องใช้โค้ดซ้ำ (boilerplate) เยอะมาก เราจึงมักทำผ่านไลบรารี JavaScript เช่น jQuery
คำขอ jQuery ดูเป็นอย่างไร:
$.get(
"/vegetables",
function(data) {
alert("Vegetables are good for you!");
}
);
อย่างไรก็ตาม ตั้งแต่ Rails 5.1 jQuery ไม่ได้มาพร้อมโดยค่าเริ่มต้น (แต่คุณเพิ่มกลับได้)
หมายเหตุ: คุณจะได้ข้อผิดพลาด
InvalidAuthenticityTokenเมื่อทำคำขอ POST ด้วย jQuery หมายความว่าคุณต้องส่งcsrf-tokenจากหน้าปัจจุบันเป็นมาตรการความปลอดภัย การใช้Rails.ajaxทำให้มันอัตโนมัติ
มีวิธีแก้!
Rails รวมฟังก์ชัน AJAX ของตัวเองไว้:
Rails.ajax({
url: "/books",
type: "get",
data: "",
success: function(data) {},
error: function(data) {}
})
จำไว้ นี่ยังคงเป็นฝั่งคำขอ (request side) จากเบราว์เซอร์
หมายความว่า นี่คือโค้ด JavaScript
ใน Rails ฟังก์ชัน AJAX นี้มาจากสิ่งที่เรียกว่า "Unobtrusive JavaScript" หรือ "UJS" เพื่อความสั้น
การอัปเดต Partial ด้วย AJAX
หากคุณต้องการอัปเดตเพียงส่วนหนึ่งของหน้าด้วยข้อมูลที่ได้จาก AJAX คุณมี 2 ทางเลือกหลัก
- คุณสามารถเขียนมุมมอง JavaScript + ERB ซึ่งอัปเดตองค์ประกอบ
- คุณสามารถส่งคืนการตอบสนอง JSON จากคอนโทรลเลอร์พร้อม HTML ใหม่เป็นสตริง แล้วใช้ JavaScript อัปเดตองค์ประกอบ
ยังมีทางเลือกที่ 3 อีก
เกี่ยวกับการส่งคืน เฉพาะข้อมูลเป็น JSON แล้วสร้างองค์ประกอบ HTML ด้วย JavaScript โดยใช้ข้อมูลนั้น
นี่คือที่มาของเฟรมเวิร์ก JS เช่น React
ลัทธิของผมคือ พวกมันเพิ่ม ความซับซ้อนที่ไม่จำเป็น มากเกินไป
แต่เราสามารถจัดการได้ด้วย JavaScript ธรรมดา!
นั่นคือทางเลือก 1 และ 2
มาคงอยู่กับสองอย่างนี้ก่อน 🙂
ตัวอย่างมุมมอง JavaScript:
Rails.$('.random-number')[0].innerHTML = ("<%= j (render partial: 'random') %>")
jเป็นอีเลียสของescape_javascript
ตัวอย่าง jQuery:
$('.random-number').html("<%= j (render partial: 'random') %>")
ทั้ง html และ innerHTML แทนที่เนื้อหาขององค์ประกอบเป้าหมาย
คุณยังสามารถผนวก (append ด้วย jQuery) องค์ประกอบใหม่เข้าไปในรายการ แทนการแทนที่ทั้งหมด
วางโค้ดนี้ในไฟล์ที่มีนามสกุล .js.erb ชื่อตรงกับการกระทำปัจจุบัน (เช่น create.js.erb) และอยู่ในโฟลเดอร์ views
บนคอนโทรลเลอร์ คุณสามารถเรนเดอร์มุมมองนี้ได้เหมือนมุมมองทั่วไป
ตอนนี้:
เมื่อคุณสร้างคำขอ AJAX โค้ด JavaScript นี้จะรันอัตโนมัติและอัปเดต HTML
มา看看ทางเลือกที่ 2
โค้ดคอนโทรลเลอร์:
render json: { html: render_to_string(partial: 'random') }
จากโค้ด JavaScript ของคุณ:
Rails.ajax({
url: "/books",
type: "get",
success: function(data) {
Rails.$(".random-number")[0].innerHTML = data.html;
}
})
นี่คืออีกวิธีหนึ่ง!
ควรใช้ตัวไหน?
DHH ชอบวิธีแรก ซึ่งเขาเรียกว่า "SJR" (Server-Generated JavaScript)
ผมเดาว่านี่คือวิธีที่ Rails ต้องการให้คุณทำ แต่ลองทำทั้งสองอย่าง (SJR และ render_to_string) เองดู แล้วดูว่าอันไหนเหมาะกับคุณกว่า
วิธีใช้ HAML สำหรับมุมมอง JS
ตกละ
สมมติว่าคุณเป็นผู้ใช้ HAML
เป็นไปได้ไหมที่จะใช้เทคนิค SJR นี้และเรนเดอร์มุมมอง .js.haml?
ได้!
ตัวอย่าง:
- content = j (render partial: "random")
Rails.$('.random-number')[0].innerHTML = ("#{content}")
มันดูแย่กว่าเวอร์ชัน ERB นิดหน่อย แต่มันทำงานได้
วิธีส่งฟอร์ม Rails โดยไม่รีเฟรชหน้า
หากคุณต้องการส่งฟอร์มด้วย AJAX คุณสามารถทำได้โดยไม่ต้องเขียนคำขอ AJAX
Rails จัดการให้คุณ
อย่างไร?
ใช้ตัวเลือก remote: true กับ form_for
ตัวอย่าง:
<%= form_for @fruit, remote: true do |f| %> <%= f.label :name, 'Fruit' %> <%= f.text_field :name %> <%= f.submit 'Create' %> <% end %>
ตอนนี้เมื่อคุณคลิก "Create" Rails จะส่งคำขอ AJAX ให้คุณ และหน้าจะไม่โหลดใหม่
หากคุณต้องการ แสดงข้อผิดพลาดการตรวจสอบความถูกต้อง คุณจะต้องสร้างและเรนเดอร์มุมมอง JavaScript (.js.erb ไฟล์) ที่แทนที่ข้อผิดพลาดปัจจุบันด้วยข้อผิดพลาดใหม่
เหมือนตัวอย่างใน "การอัปเดต Partial ด้วย AJAX"
ก็อีกอย่าง ตัวเลือก remote นี้ใช้กับลิงก์ได้ด้วย ดังนั้นคุณจึงสามารถทำคำขอ AJAX delete ได้
ตัวอย่าง:
<%= link_to "Delete", book_path(book), { method: "delete", remote: true, data: { confirm: "Are you sure?" } }
คุณสามารถจัดการการตอบสนองโดยใช้มุมมอง JavaScript
หากคุณต้องการจัดการทั้งคำขอ HTML (มาจากการโหลดหน้าใหม่) และคำขอ AJAX คุณจะต้องใช้อย่างเช่นเมธอด respond_to
ตัวอย่าง:
respond_to do |f|
f.html { redirect_to :index }
f.js
end
ในตัวอย่างนี้ อาจจะง่ายกว่าที่จะปล่อยให้ Turbolinks จัดการ
คุณยังคงสามารถทำคำขอ AJAX และ redirect_to จากคอนโทรลเลอร์ (โดยไม่ต้อง respond_to) แล้ว Turbolinks จะแทนที่เนื้อหาของหน้าโดยไม่โหลดใหม่
AJAX ไม่ทำงาน? นี่คือเคล็ดลับบางอย่าง
ถ้าคำขอ AJAX ของคุณไม่ทำงาน คุณมีการดีบัก (debug) ที่ต้องทำ
ก่อนอื่น เปิดเครื่องมือนักพัฒนาเบราว์เซอร์
คุณต้องการ ดูแผงคอนโซลหาข้อผิดพลาด JavaScript
แก้ไขมัน
นอกจากนี้ ตรวจสอบว่า CSS selector ที่คุณกำลังเป้าหมายถูกต้อง และไม่มีข้อผิดพลาดพิมพ์
จากนั้น ตรวจสอบ rails logs หาข้อผิดพลาด
จากนั้น ตรวจสอบว่ามุมมองที่ถูกต้องกำลังถูกเรนเดอร์
หากคุณทำตามกระบวนการนี้ คุณควรจะหาได้ว่าทำไมคำขอ AJAX ของคุณถึงไม่ทำงาน และแก้ไขได้
สรุป
คุณได้เรียนรู้เกี่ยวกับ AJAX เทคนิคการพัฒนาเว็บที่ช่วยให้คุณสร้างคำขอแบบอะซิงโครนัส (Asynchronous Request)!
คุณยังได้เรียนรู้วิธีนำไปใช้ใน Rails จำไว้ว่า AJAX ไม่ได้จำเป็นสำหรับการทำงานของแอป Rails ทั่วไป (non-JS framework) แต่มันเป็นเครื่องมือที่ช่วยได้ในกล่องเครื่องมือของคุณ
อย่าลืม แชร์บทความนี้ เพื่อให้คนอื่นได้ประโยชน์ 🙂
ขอบคุณที่อ่านครับ!