当前位置: 代码迷 >> 综合 >> Agile Web Development with Rails第十章笔记——任务E:更智能的购物车
  详细解决方案

Agile Web Development with Rails第十章笔记——任务E:更智能的购物车

热度:43   发布时间:2023-12-09 08:40:51.0


本章内容:

  • 修改数据库模式与现有数据
  • 诊断和处理错误
  • 闪存
  • 日志
迭代E1:创建更智能的购物车
问题提出:保存与显示购物车中同一产品的数量
解决方案:修改line_items表,添加描述数量的字段
1、使用迁移修改数据库模式
rails generate migration add_quantity_to_line_items quantity:integer

修改刚刚生成的迁移文件,将描述产品数量的字段默认值设为1
[ruby] view plain copy
  1. class AddQuantityToLineItems < ActiveRecord::Migration  
  2.   def self.up  
  3.     add_column :line_items:quantity:integer:default => 1  
  4.   end  
  5.   
  6.   def self.down  
  7.     remove_column :line_items:quantity  
  8.   end  
  9. end  
将迁移应用到数据库:
rake db:migrate
2、修改Cart模型层文件
添加add_product方法判断购物车中是否已经存在该商品。
若存在——增加数量
不存在——生成新的LineItem
[ruby] view plain copy
  1. class Cart < ActiveRecord::Base  
  2.   has_many :line_items:dependent => :destroy  
  3.   
  4.   def add_product(product_id)  
  5.     current_item = line_items.find_by_product_id(product_id)  
  6.     if current_item  
  7.       current_item.quantity += 1  
  8.     else  
  9.       current_item = line_items.build(:product_id => product_id)  
  10.     end  
  11.     current_item  
  12.   end  
  13. end  
3、修改在线商品控制器,使用第二步定义的add_product方法
[ruby] view plain copy
  1. def create  
  2.   @cart = current_cart  
  3.   product = Product.find(params[:product_id])  
  4.   @line_item = @cart.add_product(product.id)  
  5.   
  6.   respond_to do |format|  
  7.     if @line_item.save  
  8.       format.html { redirect_to(@line_item.cart,  
  9.         :notice => 'Line item was successfully created.') }  
  10.       format.xml  { render :xml => @line_item,  
  11.         :status => :created:location => @line_item }  
  12.     else  
  13.       format.html { render :action => "new" }  
  14.       format.xml  { render :xml => @line_item.errors,  
  15.         :status => :unprocessable_entity }  
  16.     end  
  17.   end  
  18. end  
修改视图文件,显示信息。
[ruby] view plain copy
  1. <h2>Your Pragmatic Cart</h2>  
  2. <ul>      
  3.   <% @cart.line_items.each do |item| %>  
  4.     <li><%= item.quantity %> × <%= item.product.title %></li>  
  5.   <% end %>  
  6. </ul>  
此时的显示结果如下所示:

这时,每行分别显示数量和书籍名称字段,只是数量字段均为默认值1,并没有实际显示购物车中该商品数量。
4、应用数据迁移修改数据表中购物车的存储信息(删除重复商品→数量*创建单一条目)
创建迁移 rails generate migration combine_items_in_cart

修改生成的迁移文件,整合购物车中的商品显示条目
实现思路:
                                                              
[ruby] view plain copy
  1. def self.up  
  2.   # replace multiple items for a single product in a cart with a single item  
  3.   Cart.all.each do |cart|  
  4.     # count the number of each product in the cart  
  5.     sums = cart.line_items.group(:product_id).sum(:quantity)  
  6.   
  7.     sums.each do |product_id, quantity|  
  8.       if quantity > 1  
  9.         # remove individual items  
  10.         cart.line_items.where(:product_id=>product_id).delete_all  
  11.   
  12.         # replace with a single item  
  13.         cart.line_items.create(:product_id=>product_id, :quantity=>quantity)  
  14.       end  
  15.     end  
  16.   end  
  17. end  
迁移应用
rake db:migrate
这里在迁移的时候产生了一个错误

错误信息很熟悉,跟第九章同样的错误。于是修改模型文件,将quantity和product_id属性放入其中。
此时可以看到购物车中的重复条目被成功整合。
5、对应于4中的self.up,完成self.down方法
根据迁移的重要原则:每一步都要是可逆的,改写self.down方法
[ruby] view plain copy
  1.   def self.down  
  2.     # split items with quantity>1 into multiple items  
  3.     LineItem.where("quantity>1").each do |line_item|  
  4.       # add individual items  
  5.       line_item.quantity.times do   
  6.         LineItem.create :cart_id=>line_item.cart_id,  
  7.           :product_id=>line_item.product_id, :quantity=>1  
  8.       end  
  9.   
  10.       # remove original item  
  11.       line_item.destroy  
  12.     end  
  13.   end  
  14. end  
完成之后通过命令回滚迁移rake db:rollback
迭代E2:错误处理
上一步完成的程序不够健壮友好,用户通过在地址栏输入无效信息可以看到如下的报错页面。
出错代码为@cart=Cart.find(params[:id]),未找到id号为44的购物车,因此报出异常。
针对该异常,我们下面采取了两个动作。
a、用rails日志功能记录相关错误
b、将页面重定向到目录页,并给出相关提示
对购物车控制器做出修改如下:
[ruby] view plain copy
  1. def show  
  2.     begin  
  3.       @cart = Cart.find(params[:id])  
  4.     rescue ActiveRecord::RecordNotFound  
  5.       logger.error "Attempt to access invalid cart #{params[:id]}"  
  6.       redirect_to store_url, :notice => 'Invalid cart'  
  7.     else  
  8.       respond_to do |format|  
  9.         format.html # show.html.erb  
  10.         format.xml  { render :xml => @cart }  
  11.       end  
  12.     end  
  13.   end  
修改之后进行测试,手动输入无效购物车id之后,页面自动跳转,并在页面上给出提示:

错误日志中记录的相关信息如下:

迭代E3:对购物车的最后加工
实现目标:清空购物车
实现思路:
a、页面添加相关链接
b、修改Cart控制器中的destory方法
1、添加相关按钮
[ruby] view plain copy
  1. <h2>Your Pragmatic Cart</h2>  
  2. <ul>      
  3.   <% @cart.line_items.each do |item| %>  
  4.     <li><%= item.quantity %> × <%= item.product.title %></li>  
  5.   <% end %>  
  6. </ul>  
  7.   
  8. <%= button_to 'Empty cart'@cart:method => :delete,  
  9.     :confirm => 'Are you sure?' %>  
2、修改destroy方法
获取用户当前购物车——删除购物车数据——从会话中删除购物车——重定向到索引页面
[ruby] view plain copy
  1.   def destroy  
  2.     @cart = current_cart  
  3.     @cart.destroy  
  4.     session[:cart_id] = nil  
  5.   
  6.     respond_to do |format|  
  7.       format.html { redirect_to(store_url,  
  8.         :notice => 'Your cart is currently empty') }  
  9.       format.xml  { head :ok }  
  10.     end  
  11.   end  
  12. end  
现在点击Empty Cart按钮,网页自动回到带有提示信息的目录页面


3、修改界面布局,展示商品价格
欲将购物车展示页面修改为:

用CSS制作购物车展示页面的样式
[ruby] view plain copy
  1. <div class="cart_title">Your Cart</div>  
  2. <table>  
  3.   <% @cart.line_items.each do |item| %>  
  4.     <tr>  
  5.       <td><%= item.quantity %>×</td>  
  6.       <td><%= item.product.title %></td>  
  7.       <td class="item_price"><%= number_to_currency(item.total_price) %></td>  
  8.     </tr>  
  9.   <% end %>  
  10.   
  11.   <tr class="total_line">  
  12.     <td colspan="2">Total</td>  
  13.     <td class="total_cell"><%= number_to_currency(@cart.total_price) %></td>  
  14.   </tr>  
  15.   
  16. </table>  
  17.   
  18. <%= button_to 'Empty cart'@cart:method => :delete,  
  19.     :confirm => 'Are you sure?' %>  

为了显示各个在线商品条目价格和购物车中商品总价格,页面代码中调用了item.total_price和@cart.total_price方法。下面分别在line_item和cart模型方法中添加这两种方法。

item.total_price

[ruby] view plain copy
  1. def total_price  
  2.   product.price * quantity  
  3. end  
cart.total_price
[ruby] view plain copy
  1. def total_price  
  2.   line_items.to_a.sum { |item| item.total_price }  
  3. end  
然后在depot.css样式表中添加欲修改的样式
[ruby] view plain copy
  1. #store .cart_title {   
  2.   font: 120% bold;  
  3. }  
  4.   
  5. #store .item_price, #store .total_line {   
  6.   text-align: right;  
  7. }  
  8.   
  9. #store .total_line .total_cell {   
  10.   font-weight: bold;  
  11.   border-top: 1px solid #595;  
  12. }  
章节复习回顾:
1、在现有的数据表中添加带有默认值的字段
添加字段:rails generate migration add_字段名_to_表名 字段名:字段类型
指定默认值:修改迁移文件
2、为检测的错误提供闪存通知
使用方法::notice=>'XXX'

  相关解决方案