Rails之购物车

跟着agile_web_development_with_rails_3rd_edition.pdf教材实现一个购物车的程序

1,使用session存储用户购买信息

2,结合form_tag的remote功能以及jquery实现刷新部分页面

> rails -v

3.2.13

记录购物车部分关键代码如下:

view/layout/store.html.erb

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
  <title>Pragprog Books Online Store</title>
  <%= stylesheet_link_tag "depot", :media => "all" %>
  <%= javascript_include_tag "application" %>
</head>
<body id="store">
  <div id="banner">
    <%= @page_title || "Pragmatic Bookshelf" %>
  </div>
  <div id="columns">
    <div id="side">
	  <!-- 动态变化部分,使用_cart.html.erb模板 -->
	  <div id="cart">
        <%= render(:partial => "cart" , :object => @cart) %>
      </div>
      <a href="http://www....">Home</a><br />
      <a href="http://www..../faq">Questions</a><br />
      <a href="http://www..../news">News</a><br />
      <a href="http://www..../contact">Contact</a><br />
    </div>
    <div id="main">
	  <!-- 只显示一次flash数值,一般用于错误提示 -->
	  <% if flash[:notice] -%>
        <div id="notice"><%= flash[:notice] %></div>
      <% end -%>
	  <!-- 加载 index.html.erb 替换于此 -->
      <%= yield :layout %>
    </div>
  </div>
</body>
</html>

view/store/index.html.erb

<h1>购物清单</h1>
<% for product in @products %>
<div class="entry">
<%= image_tag(product.image_url) %>
<h3><%=h product.title %></h3>
<%= product.description %>
<div class="price-line">
<span class="price" ><%= number_to_currency(product.price) %></span>
<!-- 关键代码,使用form_tag,设置remote -->
<%= form_tag({:action => 'add_to_cart', :id => product}, :remote => true) do %>
<%= submit_tag "Add to Cart" %>
<% end %>
</div>
</div>
<% end %>

 model部分代码如下

model/cart_item.rb

class CartItem
  attr_reader :product, :quantity
  def initialize(product)
    @product = product
    @quantity = 1
  end
  def increment_quantity
    @quantity += 1
  end
  def title
    @product.title
  end
  def price
    @product.price * @quantity	#商品花费
  end
end

model/cart.rb

class Cart
  attr_reader :items   
  
  def initialize
    @items = []	#初始化购物车
  end
  
  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)	#否则,新建商品ID,存入购物车
      @items << current_item
    end
	current_item
  end
  
  def total_price
    @items.sum { |item| item.price } #计算总价格
  end
  
end

controller部分

class StoreController < ApplicationController
  def index
    @products = Product.find_products_for_sale
	@cart = find_cart
  end
  
  def add_to_cart
    begin
	  product = Product.find(params[:id])	#错误商品ID,记录日志以及flash变量
    rescue ActiveRecord::RecordNotFound
	  logger.error("Attempt to access invalid product #{params[:id]}")
	  flash[:notice] = "Invalid product"
	  redirect_to :action => 'index'
	else									#查询已购商品发送给add_to_cart.js.erb模板执行
	  @cart = find_cart                   
      @current_item = @cart.add_product(product)
	  respond_to do |format|
        format.js	#use add_to_cart.js.erb to render
      end
    end	  
  end

  def empty_cart
    session[:cart] = nil
    flash[:notice] = "Your cart is currently empty"
	@cart = find_cart
	respond_to do |format|
       format.js	#use add_to_cart.js.erb to render
    end
  end
  
private

  def find_cart
    session[:cart] ||= Cart.new
  end
  
  def redirect_to_index(msg = nil)
    flash[:notice] = msg if msg
    redirect_to :action => 'index'
  end
end

 此外还有供前端调用的回调部分代码

view/store/add_to_cart.js.erb

//add_to_cart(action)会将这段代码传给浏览器执行
$('#cart').html("<%= escape_javascript(render(:partial => "cart" , :object => @cart)) %>");

view/store/empty_cart.js.erb

//empty_cart(action)会将这段代码传给浏览器执行
$('#cart').html("<%= escape_javascript(render(:partial => "cart" , :object => @cart)) %>");

 partial部分代码

view/store/_cart.html.erb

<% unless cart.items.empty? %>
<div class="cart-title">Your Cart</div>
<table>
<!-- 使用_cart_item.html.erb模板 -->
<%= render(:partial => "cart_item" , :collection => cart.items) %>
<tr class="total-line">
<td colspan="2">Total</td>
<td class="total-cell"><%= number_to_currency(cart.total_price) %></td>
</tr>
</table>
<!-- 清空购物车按钮,也是远程调用无刷新更改页面 -->
<%= form_tag({:action => 'empty_cart'}, :remote => true) do %>
<%= submit_tag "Empty Cart" %>
<% end %>
<% end %>

view/store/_cart_item.html.erb

<% 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"><%= number_to_currency(cart_item.price) %></td>
</tr>

猜你喜欢

转载自ciaos.iteye.com/blog/1861189