實作當用戶登出時保留購物車內容

在第二週的rails即戰力班的artstore購物網站教學裡,有教到利用session來記住購物車的cart_id

application_controller.rb
def find_cart
    cart = Cart.find_by(id: session[:cart_id])
    unless cart.present?
      cart = Cart.create
    end
    session[:cart_id] = cart.id
    cart
  end
end

作法就是如果session裡有cart_id的話就取這個id,沒有的話就產生一筆新的cart資料,簡單的來說就是你有號碼牌我就給你那個號碼的車子,沒有號碼牌的話我就給你一台新的車。

但其實這邊有個問題,那就是專案裡有用到devise去實作會員系統,當登出會員的時候devise會去清空所有session,以至於下次登入的時候就又會拿到一台新的車子,在不同帳號登入登出的情況下,就會變成在cart table裡有很多用過一次就廢棄在那邊的購物車

這裡插播一下要避免devise清掉session的方法,在stackoverflow找了一下找到了這個文章
Stop Devise from clearing session
在第二個answer的地方有提到config.sign_out_all_scopes = false
這邊就是去config/devise.rb裡找到這一行,把註解拿掉並改成false,然後rails s重開,這樣登出的時候session就不會被清掉了。

回到正題如果用戶登出然後要記住用戶之前所選購的商品,在下次用戶再次登入時可以直接提醒他上次有選購但未結帳的商品的話有兩種做法,第一種就是把用戶名稱跟所屬的cart_id用session或cookies儲存起來,如果用session儲存的話記得要先去修改剛剛提到devise清除session的問題,假設我儲存在cookies裡所以當產生新的購物車時我會用使用者的email來當作cookies的key值,然後在裡面再包一個hash去儲存cart_id像這樣

<% cookies[current_user.email] = JSON.generate ({"cart_id" => 1}) %>

這邊有點要注意的是因為cookies沒辦法接收hash所以我用了JSON編譯過後把資料塞進去,之後要從cookies裡面取值的話可以這麼做

<%= JSON.parse(cookies[current_user.email])["cart_id"] %>

之後就直接去cart_items裡面找到上次有加到購物車的商品列出來。
第一種是比較簡單的方式,不用開tabel出來透過cookies來儲存資料,但其實這邊會有另外一個問題就是如果用戶把瀏覽器的cookies清除的話下次進來就會找不到資料,然後又只好給一個新的購物車然後cart跟cart_items就又會多了一些再也用不到的資料。

第二種方式就比較hard way但實作的概念是差不多的,我的做法是先開一個假設叫user_cart的model,這個model去當作一個對照表,分別記錄著user_id跟cart_id,這樣用戶在登入的時候靠著user_id去這邊就可以找到對應到的cart,然後再拿著cart_id去cart_items就可以找到上次有加入購物車的產品。如果沒有車的話當然就先給一台但我會再用戶第一次把商品加入購物車時才會給他車

第二種的做法code還在實作中等弄完再貼上來

這樣子的做法有點像是有加入會員的人都可以得到一台專屬的購物車,要買東西的話就都用這一台,即使用戶已經結帳商品並且清空購物車但這台購物車仍會存在,他只是裡面被清空放在這個賣場裡的某個角落

之前有想過要不要把cart_id放在user table裡或是把user_id放在cart table裡,但後來還是覺得不管是user或是cart都還是放跟自己相關的東西就好

這種登出之後還可以記住上次加入購物車的商品的做法就沒有考慮到如果沒有加入會員到底能不能購物,是一定要加入才能購物呢?還是可以先購物再加入會員,因為這樣的延伸性可能就會有點多就先不討論,如果有更好的做法或建議的話可以留言討論一下

comments powered by Disqus