上一節:Ruby on Rails實戰–創建一個網上商店B前台
本節將向商店加入一個Ajax購物籃,使商店產品列表在不刷新的情況下更新顯示購物籃信息
修改depot/app/controllers/store_controller.rb文件,如下:
def index
@products = Product.find_products_for_sale
@cart = find_cart #加入對@cart的定義
end
def add_to_cart
begin
@product = Product.find(params[:id])
rescue
logger.error("Attempt to access invalid product #{params[:id]}")
redirect_to_index("Invalid product")
else
@cart = find_cart
@current_item = @cart.add_product(@product)
redirect_to_index unless request.xhr?
#request.xhr判斷是否xmlHttpRequest, 否將指向index action, 用來兼容關閉了javascript功能的瀏覽器
#開發時以無Ajax的為藍本,再修改到ajax,以方便兼容性處理
end
end
#….
private
def redirect_to_index(msg = nil)
#msg = nil 指定msg的默認值, 如果msg沒有說明, msg = nil.
flash[:notice] = msg if msg
#加入對無參數的支持
redirect_to :action => :index
end
#…
修改depot/app/models/cart.rb文件,如下:
def add_product(product)
current_item = @items.find {|item| item.product == product}
if current_item
current_item.increment_quantity
else
current_item = CartItem.new(product)
@items << current_item
end
current_item #新加,使返回修改商品
end
修改depot/app/controllers/store_controller.rb文件,如下:
def add_to_cart
begin
@product = Product.find(params[:id])
rescue
logger.error("Attempt to access invalid product #{params[:id]}")
redirect_to_index("Invalid product")
else
@cart = find_cart
@current_item = @cart.add_product(@product) #新加,定義@current_item
end
end
#….
def empty_cart
session[:cart] = nil
redirect_to_index #清空購物籃後返回商品列表
end
#…
修改depot/app/models/cart.rb文件,增加一個購物籃內商品數據變量
def total_items
@items.inject(0) {|sum, item| sum + item.quantity}
end
在depot/app/views/store/index.rhtml
中將:
<%= button_to "Add to Cart", :action => :add_to_cart, :id => product %>
改為:
<%= form_remote_tag :url => { :action => :add_to_cart, :id => product } %>
<%= submit_tag "Add to Cart" %>
<%= end_form_tag %>
在depot/app/views/layouts/store.rhtml文件里加入模板對javascript的支持,如下:
<html>
<head>
<title>Pragprog Books Online Store</title>
<%= stylesheet_link_tag "depot", :media => "all" %>
<%= javascript_include_tag :defaults %>
</head>
在depot/app/views/store/新加一個partial template _cart.rhtml,內容如下:
<div class="cart-title">Your Cart</div>
<table>
<%= render(:partial => "cart_item", :collection => cart.items) %>
<!–調用另一個partial template _cart_item.rhtml–>
<tr class="total-line">
<td colspan="2">Total</td>
<td class="total-cell"><%= format_price(cart.total_price) %></td>
</tr>
</table>
<%= button_to "Empty cart", :action => :empty_cart %>
partial template以下找線開頭,由render的調用.
在depot/app/views/store/新加一個partial template _cart_item.rhtml,內容如下:
<% if cart_item == @current_item %>
<!–後面用來顯示特殊效果–>
<tr id="current_item">
<% else %>
<tr>
<% end %>
<td><%= cart_item.quantity %>×</td>
<td><%= h(cart_item.title) %></td>
<td class="item-price"><%= format_price(cart_item.price) %></td>
</tr>
在depot/app/views/layouts/store.rhtml文件中增加調用partial template的代碼:
<div id="side">
<%= hidden_div_if(@cart.items.empty?, :id => "cart") %>
<!–hidden_div_if 這個 helpper method用來向div加入display:none屬性, 代碼見下文–>
<%= render(:partial =>"cart", :object => @cart) %>
</div>
…..
創建hidden_div_if helpper method
def hidden_div_if(condition, attributes = {})
if condition
attributes["style"] = "display: none"
end
attrs = tag_options(attributes.stringify_keys)
"<div #{attrs}>"
end
刪除不用了的add_to_cart.rhtml
新建depot/app/views/store/add_to_cart.rjs文件,內容如下:
page[:cart].replace_html :partial => ‘cart’, :object => @cart
#將頁面中id=cart的元素換成partial _cart.rhtml的內容
page[:cart].visual_effect :blind_down if @cart.total_items == 1
#當向購物籃添加第一個商品時,特效顯示出購物籃
page[:current_item].visual_effect :highlight,
:startcolor =>"#88ff88",
:endcolor =>"#114411"
#當購物籃商品發生變化時,特效顯示變化行
本節完成,為使ajax效果生效, 我重新啟動了服務器
下一節:Ruby on Rails實戰–創建一個網上商店D收銀台
本文最後更新 20070108
轉載請註明: 轉自船長日誌, 本文鏈接地址: http://www.cslog.cn/Content/ruby_on_rails_ajax_eshop/zh-hant/