跟着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 %>×</td>
<td><%=h cart_item.title %></td>
<td class="item-price"><%= number_to_currency(cart_item.price) %></td>
</tr>