Ruby on Rails實戰–創建一個網上商店C小試Ajax

上一節: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 %>&times;</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

此條目發表在 Ruby on Rails 分類目錄。將固定鏈接加入收藏夾。

發表評論