Ruby on Rails — jQuery — AJAX

張凱喬
8 min readApr 16, 2018

--

承接上篇所提,我們利用jQuery的AJAX功能,雖然沒有ujs的方便性,但是對未來擴增及撰寫彈性是有優勢的。

以下介紹一下,怎麼樣用jQuery完成一些AJAX功能

jQuery自帶ajax方法
但是在rails底下要注意CSRF的問題

簡單來說,就是會在網頁裡面放token,在執行網頁動作時隨附token,讓伺服器可以驗證,確保安全。

然後rails 5.1已經自帶rails-ujs.js
記得在 application.js 裡寫入//= require rails-ujs
這樣所有ajax請求都會自動被加入csrf token

這邊就開始寫ajax囉
$.ajax 方法要帶入一個 object

這邊提醒一下javascript的object寫法

物件(objects):
1. 以 {} 包含
2. 有 Key & Value , 如: var obj = { one:1, two:2, three:3, four:4, five:5 };

最基本的jquery ajax寫法包含

url:發送非同步請求的對象,也就是索求資料的 server 的網址
method:發送請求的類型,如 GET、POST、DELETE、PATCH 等
data:要附帶在請求裡發送給 server 的資料
dataType:要求 server 回傳的資料格式
success:成功後要執行的 function,function 會帶入 server 回傳的資料

以Destroy例如

$("#todolist").on("click", ".delete-todo", function(event) {
var id = event.target.parentNode.parentNode.id;
$.ajax({
url: "todos/" + id,
method: "DELETE",
dataType: "json",
success: function(data) {
$("#" + data["id"]).remove();
}
});
});

這邊用on的函式是為了解決動態的元件,如果在#todolist底下做click動作而且又是按.delete-todo這個元件,就會啟動function

上面的範例中.delete-todo是會臨時增減的,如果用傳統的click()方法寫,在動態新增.delete-todo之後,會抓不到這個新的.delete-todo

然後裡面的這個var id是用來找到@todo的id
來對應route裡面的路徑(範例中是/todos/:id(.:format))

設定好格式json,這樣子等一下可以回傳id,來執行刪除的jQuery
(其實可以直接抓上面的var id,不過習慣利用回傳的data做事情,對create、update等動作會有幫助)

所以就要把controller這邊也寫完,回傳json

def destroy
@todo = Todo.find(params[:id])
@todo.destroy
render :json => { :id => @todo.id } #就是這行
end

這樣就完成Destroy囉

再來看一下更複雜的Create
直接上程式碼

$("#create-todo").on("click", function(event) {
event.preventDefault();
$.ajax({
url: "todos/",
method: "POST",
dataType: "json",
data: {
todo: {
title: $("#new-todo").val()
}
},
success: function(data) {
}
});
});

首先,event.preventDefault()是用來阻止瀏覽器做預設的動作
在form裡的button預設的動作就是送出表單

他會自己執行post,但我們不要
因為我們要用ajax做post,不是瀏覽器做

然後再來的話設定method post, type json
並且找到對應的url,這些應該都不是問題

問題是data,在Rails 4之後加入了strong params規定
也就是寫入資料時必須先設定好傳什麼變數進來,沒有設定的就不給傳
來看一下這個範例的controller的strong params是怎麼寫的

def todo_params
params.require(:todo).permit(:title)
end

所以你要手刻傳給伺服器的資料就必須符合規定
簡單來說就是要傳一個”todo”的資料、而且裡面有title
伺服器才給放行

所以我們就把todo及title用json的寫法包起來
就可以順利的讓伺服器寫入了

然後如果你需要在同一個頁面看到你新增的結果
也是跟destroy一樣,在controller action裡寫回傳json
利用這個回傳的json,在success: function(data){}裡面做你想要做的事情

其實寫到後面發現
要作ajax這個並不難,只是如果你需要同步更新網頁
(譬如說把你新增、修改的內容要即時更新)
就會需要寫很多jQuery、javascript、HTML DOM的東西

舉例來說
在AC的課程裡,教學任務寫了如何在按下編輯之後
使todo的文字變成編輯框、編輯完送出之後馬上改變
使這些流程完全靠ajax,在寫jQuery時就會變得很複雜

可以包成像這樣的邏輯

設定 edit 按鈕事件驅動
抽換表單
設定 update 按鈕事件驅動
恢復文字欄位
結束 update 按鈕事件驅動
結束 edit 按鈕事件驅動

就會在edit按鈕的.on事件裡面放.ajax
然後success裡面 再放一個.on,再放.ajax
最後success裡面回復文字欄位這樣…

--

--

No responses yet