× 說心事 政治時事 生活 運動 汽車 機車 自行車 相機 科技 理財 旅遊美食 娛樂 健康 美麗時尚 人際關係 文學故事 關於《思書》
吃喝玩樂 關於《思書》

用 Rails + AJAX 開發一個自動儲存功能

紅寶鐵軌客
來關注...
關注:紅寶鐵軌客
關注有什麼好處?:當作者有新文章發佈時,「思書日報」就會匯總自動通知您,讓您更容易與作者互動。
x
紅寶鐵軌客
Rails 使用中,折磨中,享受中......
Victorian vintage round cut ruby engagement ring in 14k yellow gold 7mm center vs g h 984
    很久以前就是個「寫程式的」,其實,什麼程式都不熟⋯⋯
     
    就,這會一點點,那會一點點⋯⋯
作者最新發佈的文章:
  • 在 Linux 中用 sendmail 代替 mail
  • self.function 遇到 self.class.function
  • 討厭的 Referer Spam
作者最近參與的討論:
  • Rails 常見資安陷阱與解決方法
現在就加入《思書》,你就可以關注本作者了!
《思書》是一個每個人的寫作與論壇平台,特有的隱私管理,讓你寫作不再受限,討論更深入真實,而且免費。 趕快來試試!
還未加入《思書》? 現在就登錄! 已經加入《思書》── 登入
Rails 使用中,折磨中,享受中......
2017/11/15
55   0  

很多網頁開發後都會被業主或是客戶要求,要跟 Google Doc 一樣,會自動儲存資料,這是一個對使用者很方便的功能,剛接到要求時,會覺得很簡單,但是我遇到了好多問題,所以我就特別把我的寫法分享出來,希望對大家有幫助,如果有更好的方法,也請讓我知道。

先講我碰到的問題,開發自動儲存功能時,一開始的想法,這應該就像一個會自動按儲存按鈕的 javascript 機器人,其實也很像,但是有一個問題讓我走了很多的冤妄路,而且就是網頁操作的基本:CRUD + REST。

CRUD 和 REST 是什麼就不多說了,但是各位會讀本文的讀者應該都知道,當使用者在新增一個產品說明時,網頁上的網址是: .../new,但是在更新產品時是: ..../123/edit,當使用者按下新增或是更新時,Controller 對應的 action 是 create 及 update,這是我們在網頁開發與 Rails 中已經用習慣了方法,實務上也很穩定,但是在開發自動儲存功能,這造成了很大的問題。

一開始我的想發很簡單,就是如果是新的 new,自動儲存後就 redirect_to edit,每次自動儲存後,再做一個 edit/update 動作,其實光改這 code 我就覺得怪怪的,就遇到很多問題,越寫越毛,後來真的就發現了,不可行,主要的問題是自動儲存後,如果使用者按了瀏覽器倒退鍵,怎麼辦?每一個 redirect_to 就會有一個瀏覽器歷史紀錄,如果使用者(1)新增一筆資料 .../new,(2)自動儲存動作,網址自動前進到 ..../123/edit,很棒啊,但是此時(3)使用者按了瀏覽器倒退鍵,又回到.../new,糟了,又新增了一筆資料了,我有嘗試要改東改西來解決這問題,很快,我就覺得這樣的方法是錯的,越改只會越讓使用者困惱,退回原點,改用以下的全 Ajax方法,還是有邏輯上的問題,使用者會看到 .../new,但是資料可能已經被 create 了,這些也可以改,但是這樣的修改這就比較像是炫技了,我覺得不必要,最少,這樣做,使用者的操作流程是直覺式的,後來也證明,這樣使用者沒問題。

如何用 Rails + AJAX 寫一個自動儲存

1. 在你要儲存的網頁中,一般都是 form partial 吧,看看有沒有你要儲存的 DB table id? 如果沒有,就加一個 <%= f.hidden_field :id %>,這個 id 就是我們等一下要用來識別這筆資料到底要新增還是更新的參考。

2. 在對應的 controller 中新增一個 autosave 動作:

# POST /autosave, for AJAX call
def autosave
if !params[:product][:id].blank?
@product = Product.find(params[:product][:id])
# update data
if @product.update(product_params)
# 更新正確
else
# 更新錯誤
end
else
@product = Product.new(product_params)
if @product.save
# 新增正確
else
# 新增錯誤
end
end
  respond_to do |format|
format.js
end
end

 

3. 接下來當然就是要有 autosave.js.erb,這裡面就看你要更新網頁什麼內容,但是一定要更新的就是這個 DB table id,不然到時又被新增了一筆資料。因為太簡單,我就直接用 Javascript 寫,各位就看個人的喜愛了,hidden_field 會自動產生 CSS ID,各位還是要自己看一下。

document.getElementById("hidden_field_product_id").value = "<%= @product.id.to_s %>"

 

4. 再來就一定要加個路徑到 routes.rb,我喜歡用 collection...

 resources :products do
collection do
# adding AJAX autosave post path
post 'posts/autosave' => 'products#autosave'
end
end

 

5. 就快寫好了,再來就是一段 AJAX,這段就是自動按儲存按鈕的 javascript

$(document).on('turbolinks:load', function() {
// 2 分鐘後自動按儲存按鈕, 2x60s = 120s = 120,000ms
if ($("#product").length > 0) {
setTimeout(autoSavePost, 120000);
};
});

function autoSavePost() {
// $("#product_id") 還是要檢查一下,不要網頁都走了,還自動儲存
if ($("#product_id").length > 0) {
var params_string = $("#product_id, #product_title, #product_desc, #product_price).serialize();
$.ajax({
type: "POST",
url: "/products/posts/autosave",
data: params_string,
dataType: "script",
success: function(data) {
console.log(data);
console.log('autosave');
}
};
// 2 分鐘後再自動按儲存按鈕, 2x60s = 120s = 120,000ms
setTimeout(autoSavePost, 120000);
};
};

就這樣,寫完了,當然如果各位有新加功能,還是有些牛鬼蛇神會出現,但是應該也不難解,希望對大家有幫助了,如果各位有更好的解法,特別是關於網址的顯示、瀏覽器倒退、瀏覽器更新、與瀏覽器歷史紀錄的改變等有使用方法,我還是很想知道,到底,網址顯示是新增,但是資料已經存了,還是怪怪的,要全改寫成 SPA?

 

關於作者
很久以前就是個「寫程式的」,其實,什麼程式都不熟⋯⋯
 
就,這會一點點,那會一點點⋯⋯


標籤: ajax x 2 自動儲存 x 1 rails x 24

分享:


參與討論!
x
現在就加入《思書》,馬上參與討論!
《思書》是一個每個人的寫作與論壇平台,特有的隱私管理,用筆名來區隔你討論內容,讓你的討論更深入,而且免費。 趕快來試試!
還未加入《思書》? 現在就登錄! 已經加入《思書》── 登入
思書 Scrivinor 不斷的在強化體驗與功能,我們很期待您的建議,請與我們聯繫: support@scrivinor.com