跟着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>