在前面的内容里,我们演示了怎样构建一个商品的列表,这次,我们在前面内容的基础上,构建一个简单的购物车。
1.首先我们要来创建一个保存客户购物信息的表:
数据库脚本:
drop table if exists line_items;create table line_items (id int not null auto_increment,product_id int not null,quantity int not null default 0,unit_price decimal(10,2) not null,constraint fk_items_product foreign key (product_id) references products(id),primary key (id));
之后在PhpMyAdmin中创建表,然后使用Rails命令行创建line_item表对应的类:
depot> ruby script/generate model LineItem
(创建的详细步骤可以参考前面的几篇随笔)
2.给LineItem和Product创建主从关系:
打开/rails_apps/depot/app/models目录下的line_item.rb文件,修改文件内容为:
class LineItem < ActiveRecord::Basebelongs_to :productend
可以看到belongs_to :product这句给LineItem和Product创建了主从关系。
3.现在,我们可以添加ruby代码了。
首先是rails_apps/depot/app/controllers目录下的sTore_controller.rb文件,给其中添加方法:
privatedef find_cartsession[:cart] ||= Cart.newend
实际上,在上篇随笔中,在rails_apps/depot/app/views/sTore目录下的index.rhtml文件中,我们可以看到这样的代码:
<%= link_to 'Add to Cart',{:action => 'add_to_cart', :id => product },:class => 'addtocart' %>
这句代码的就是给Add to Cart链接指定它的Action,相应的,我们要在sTore_controller.rb中添加add_to_cart方法
def add_to_cartproduct = Product.find(params[:id])@cart = find_cart@cart.add_product(product)redirect_to(:action => 'display_cart')end
上面的代码中,首先调用了Product的find方法,然后是sTore_controller的find_cart方法,接下来调用Cart的add_product方法,然后在重定向页面,Action是display_cart。
好了,下面我们来编写这些方法中要用到的代码。
l 创建Cart类,我们在app/models目录下,创建cart.rb文件,代码如下:
class Cartattr_reader :itemsattr_reader :total_pricedef initialize@items = []@total_price = 0.0enddef add_product(product) <<@items << LineItem.for_product(product)@total_price += product.priceendend
l 给LineItem添加一个方法for_product,代码如下:
class LineItem < ActiveRecord::Basebelongs_to :productdef self.for_product(product) self.newitem = self.newitem.quantity = 1item.product = productitem.unit_price = product.priceitemendend
l 在sTore_controller.rb文件中添加方法display_cart,代码:
def display_cart@cart = find_cart@items = @cart.itemsend
l 我们再来创建一个显示Cart的页面。
在rails_apps/depot/app/views/sTore目录下,新建,一个display_cart.rhtml文件,修改内容:
<h1>Display Cart</h1><p>Your cart contains <%= @items.size %> items.</p>
l 这时候,如果我们点击Add to Cart链接的话,会出现一个error页面,这是因为我们还没有定义session。这一步我们需要修改rails_apps/depot/app/controllers目录下的application.rb文件,使其内容为:
# Filters added to this controller apply to all controllers in the application.# Likewise, all the methods added will be available for all controllers.class ApplicationController < ActionController::Base # Pick a unique cookie name to distinguish our session data from others' #session:session_key => '_depot_session_id'model :cartmodel :line_itemend
l 到此,再点击点击Add to Cart链接,应该会出现一个正常的页面了。
4.现在,虽然我们已经有了一个可以运行的页面,但是你会发现,如果你多次添加同一件商品,在display_cart页面上会一条一条显示。我们来完善一下这些代码,修改add_product方法:
def add_product(product)item = @items.find {|i| i.product_id == product.id}if itemitem.quantity += 1elseitem = LineItem.for_product(product)@items << itemend@total_price += product.priceend
最后再美化下display_cart页面:
<html> <head> <%= stylesheet_link_tag "scaffold", "depot", "admin", :media => "all" %> </head> <div id="cartmenu"> <ul> <li><%= link_to 'Continue shopping', :action => "index" %></li> <li><%= link_to 'Empty cart', :action => "empty_cart" %></li> <li><%= link_to 'Checkout', :action => "checkout" %></li> </ul> </div> <table cellpadding="10" cellspacing="0"> <tr class="carttitle"> <td rowspan="2">Qty</td> <td rowspan="2">Description</td> <td colspan="2">Price</td> </tr> <tr class="carttitle"> <td>Each</td> <td>Total</td> </tr> <% for item in @items product = item.product -%> <tr> <td><%= item.quantity %></td> <td><%= h(product.title) %></td> <td align="right"><%= item.unit_price %></td> <td align="right"><%= item.unit_price * item.quantity %></td> </tr> <% end %> <tr> <td colspan="3" align="right"><strong>Total:</strong></td> <td id="totalcell"><%= @cart.total_price %></td> </tr> </table></html>
OK,大功告成了,来看看最后的效果:
不论你在什么时候开始,重要的是开始之後就不要停止