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

紅寶鐵軌客
Join to follow...
Follow/Unfollow Writer: 紅寶鐵軌客
By following, you’ll receive notifications when this author publishes new articles.
Don't wait! Sign up to follow this writer.
WriterShelf is a privacy-oriented writing platform. Unleash the power of your voice. It's free!
Sign up. Join WriterShelf now! Already a member. Login to WriterShelf.
寫程式中、折磨中、享受中 ......
814   0  
·
2017/11/15
·
4 mins read


很多網頁開發後都會被業主或是客戶要求,要跟 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?

 


WriterShelf™ is a unique multiple pen name blogging and forum platform. Protect relationships and your privacy. Take your writing in new directions. ** Join WriterShelf**
WriterShelf™ is an open writing platform. The views, information and opinions in this article are those of the author.


Article info

Categories:
Tags:
Date:
Published: 2017/11/15 - Updated: 2017/11/19
Total: 1170 words


Share this article:
About the Author

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




Join the discussion now!
Don't wait! Sign up to join the discussion.
WriterShelf is a privacy-oriented writing platform. Unleash the power of your voice. It's free!
Sign up. Join WriterShelf now! Already a member. Login to WriterShelf.