這兩天雖然游戲玩了一會查近,但好歹還是寫了點東西,都是邊看資料邊寫挤忙,所以顯得很混亂霜威,本來不想記下來,又怕以后忘記册烈,所以還是記下來好了戈泼。。。大猛。源碼還是在:
https://github.com/kamionayuki/shop
已經(jīng)有了products表了扭倾,所以只需要創(chuàng)建一個carts表就OK了,又因為每一個用戶有且只有一個購物車挽绩,所以carts表除了id列膛壹,就只有一列user_id。而User這個模型又devise生成(具體不就多說了)這樣唉堪,就有了products和carts兩張表模聋。購物車的話,應(yīng)該是多對多關(guān)系唠亚,一個cart可以有多個prodcuct撬槽,而一個product也可以存在多個cart中。所以最開始想到了用 has_and_belongs_to_many 來實現(xiàn) 多對多的模型關(guān)聯(lián)趾撵。所以創(chuàng)建了一張表:carts_products 只有兩列:cart_id 和 product_id然后就可以用關(guān)聯(lián)生成的方法cart.products.size來查詢cart中有多少product侄柔。也可以通過代碼來排重,查詢有多少種product占调,甚至可以查詢每一種product有多少個暂题。
到現(xiàn)在,一切看起來很順利究珊。薪者。。剿涮。但是有兩個隱患
- 如果這樣關(guān)聯(lián)的話言津,carts_products這張表,就會很大很大取试。如果一個cart中只有一個product悬槽,但這個product有1000個,那么瞬浓,carts_products表里就會有1000行數(shù)據(jù)初婆,明顯不科學(xué)。猿棉。磅叛。
- 沒有辦法去一件一件的刪除cart中的product。如果一個product有10件萨赁,用delete和destroy都是直接把這10件都刪除掉了弊琴。也不科學(xué)。杖爽。敲董。
發(fā)愁了紫皇,想到了增加product_number這一列來記錄某一類product有多少個。但是怎么去操作呢臣缀?只能找資料了坝橡。。精置〖瓶埽看了一下,似乎 has_many 好像可以滿足脂倦。于是
rails g model CartRelationship cart_id:integer product_id:integer product_number:integer
生成一個中間模型番宁,同時用carts_relationships 這張表來做中間表進行操作。model中的代碼如下:
app/models/cart.rb
has_many :cart_relationships
has_many :products, through: :cart_relationships
app/models/product.rb
has_many :cart_relationships
has_many :carts, through: :cart_relationships
app/models/cart_relationship.rb
belongs_to :cart
belongs_to :product
這樣就關(guān)聯(lián)好了赖阻。但還是一樣蝶押,沒有辦法去一件一件的刪除cart中的product。并且用cart.products << @product的時候火欧,也不會對product_number這一列進行操作棋电。所以只能自己在cart.rb中寫add和delete的方法了
具體代碼如下:
def delete_from_cart(product)
result = select_cart_relationship(product)
if 1 == result.product_number
self.products.destroy(product)
else
result.product_number -= 1
result.save
end
end
def add_to_cart(product)
if self.products.exists?(product)
result = select_cart_relationship(product)
result.product_number += 1
else
self.products << product
result = select_cart_relationship(product)
result.product_number = 1
end
result.save
end
def select_cart_relationship(product)
query = "select * from cart_relationships where cart_id = %d && product_id = %d" % [self.id, product.id]
temp = CartRelationship.find_by_sql(query).first
end
其中的關(guān)鍵在 select_cart_relationship 這個方法。通過find_by_sql的方法進行查詢苇侵,得到一個數(shù)組赶盔,然后取第一個元素。
它返回的值是一個CartRelationship的實例榆浓,這個實例有id,cart_id,product_id以及product_number的屬性于未。
因此,我們就可以對Product_number進行更新和保存陡鹃。邏輯直接看代碼就OK了烘浦。
至此,我們可以通過cart.products來得到cart中擁有的product的種類
然后通過 select_cart_relationship(product).product_number這個方法來得到某一類product有多少個萍鲸。所以我們也可以用以下的代碼來得到這個cart中所有的product的個數(shù)
@cart.products.inject(0) do |result, p|
result += @cart.select_cart_raletionship(p).product_number
end
但是看后臺數(shù)據(jù)庫的執(zhí)行闷叉,如果cart中有100類product,那么就會執(zhí)行100次查詢猿推,雖然不知道性能會怎么樣片习,但看起來太嚇人了,所以又開始查資料蹬叭,最后用下面的方法實現(xiàn)了:
def product_count
sql = ActiveRecord::Base.connection()
query = "select sum(product_number) sum from cart_relationships group by cart_id having cart_id=%d" % self.id
sql.exec_query(query).sum["sum"]
end
具體里的的邏輯不太了解,但從表面上來看:是先實例化了一個數(shù)據(jù)庫鏈接的實例
然后通過這個實例調(diào)用exec_query來直接執(zhí)行mysql語句状知。
tips:可以先把mysql語句在數(shù)據(jù)庫中執(zhí)行一下秽五,看是否正確
這樣每查詢一次cart中所有的product的個數(shù),只需要執(zhí)行一次查詢就OK了饥悴。但由于是邊看資料邊寫的坦喘,所以每調(diào)用一次product_count方法盲再,就需要實例一個數(shù)據(jù)庫鏈接的實例,可能也是蠻耗資源的瓣铣?總之答朋,數(shù)據(jù)庫操作是實現(xiàn)了。
那么controller和views中就好辦了棠笑。只需要寫邏輯就可以了
*controller中梦碗,購物車肯定是用ajax更好,所以還是繼續(xù)ajax蓖救。
class CartsController < ApplicationController
before_action :authenticate_user!, only: [:show]
def show
@cart = current_user.cart
end
def add_to_cart
if !current_user.nil?
@product = Product.find(params[:product_id])
@cart = current_user.cart
@cart.add_to_cart(@product)
@total_count = @cart.product_count
@product_count = @cart.select_cart_relationship(@product).product_number
flash.now[:notice] = "成功添加1件#{@product.name}到購物車"
render 'change_cart'
else
flash[:notice] = 'please sign in first.'
flash.keep(:notice)
render js: "window.location = '/users/sign_in'"
end
end
def delete_from_cart
if !current_user.nil?
@product = Product.find(params[:product_id])
@cart = current_user.cart
@cart.delete_from_cart(@product)
@total_count = current_user.cart.product_count
if @cart.products.exists?(@product)
@product_count = @cart.select_cart_relationship(@product).product_number
flash.now[:notice] = "已經(jīng)刪除1件#{@product.name}"
render 'change_cart'
else
flash.now[:notice] = "刪除了最后一件#{@product.name}"
render 'delete_from_cart'
end
else
flash[:notice] = 'please sign in first.'
flash.keep(:notice)
render js: "window.location = '/users/sign_in'"
end
end
end
views中(其中還學(xué)到了在js.erb文件中洪规,<%= render text%>可以嵌入在 "" 字符串中的任意位置):
change_cart.js.erb
var total_count = "Cart(<%= render text: @total_count %>)";
var summary = "共<%= render text: @cart.product_count %>件物品,總計<%= render text: @cart.total_summary %>";
//更新頁面上總個數(shù)和總價顯示
$(".cart_count").text(total_count);
$(".summary").text(summary);
//更新提示
$("#sidebar_nav").next().remove();
$("#sidebar_nav").after("<%= j render('layouts/flash') %>");
//更新列表中某一類product的個數(shù)
var xx = $("a[href$='add_to_cart/<%= render text: @product.id %>']");
xx.prev().text("<%= render text: @product_count %>");
delete_from_cart.js.erb
//與change_cart.js.erb類似循捺,只是把數(shù)量為0的product移除不顯示
var total_count = "Cart(<%= render text: @total_count %>)";
var summary = "共<%= render text: @cart.product_count %>件物品斩例,總計<%= render text: @cart.total_summary %>";
//更新頁面上總個數(shù)和總價顯示
$(".cart_count").text(total_count);
$(".summary").text(summary);
//更新提示
$("#sidebar_nav").next().remove();
$("#sidebar_nav").after("<%= j render('layouts/flash') %>");
//移除數(shù)量為0的product的顯示
var xx = $("a[href$='add_to_cart/<%= render text: @product.id %>']");
xx.parent().parent().remove();
好了,就這樣吧从橘。念赶。。估計過段時間再來看也不大會看得懂恰力。叉谜。。牺勾。正罢。