本章内容:
<div class="cart_title">Your Cart</div> <table> <% @cart.line_items.each do |item| %> <tr> <td><%= item.quantity %>×</td> <td><%= item.product.title %></td> <td class="item_price"><%= number_to_currency(item.total_price) %></td> </tr> <% end %> <tr class="total_line"> <td colspan="2">Total</td> <td class="total_cell"><%= number_to_currency(@cart.total_price) %></td> </tr> </table> <%= button_to 'Empty cart', @cart, :method => :delete, :confirm => 'Are you sure?' %>下面我们要做的是将这个循环抽象化,即定义一个显示在线商品的局部模版(向其中传递集合),购物车页面调用该模板即可。
<tr> <td><%= line_item.quantity %>×</td> <td><%= line_item.product.title %></td> <td class="item_price"><%= number_to_currency(line_item.total_price) %></td> </tr>
<div class="cart_title">Your Cart</div> <table> <%= render(cart.line_items) %> <tr class="total_line"> <td colspan="2">Total</td> <td class="total_cell"><%= number_to_currency(cart.total_price) %></td> </tr> </table> <%= button_to 'Empty cart', cart, :method => :delete, :confirm => 'Are you sure?' %>如上<%=render(cart.line_items)%>所示,使用render方法加载在线产品的模板。
<!DOCTYPE html> <html> <head> <title>Pragprog Books Online Store</title> <%= stylesheet_link_tag "scaffold" %> <%= stylesheet_link_tag "depot", :media => "all" %> <%= javascript_include_tag :defaults %> <%= csrf_meta_tag %> </head> <body id="store"> <div id="banner"> <%= image_tag("logo.png") %> <%= @page_title || "Pragmatic Bookshelf" %> </div> <div id="columns"> <div id="side"> <div id="cart"> <%= render @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"> <%= yield %> </div> </div> </body> </html>在上面页面中使用了@cart变量,因而需要在控制器中定义该变量
def index @products = Product.all @cart = current_cart end再加入CSS控制样式
#cart, #cart table { font-size: smaller; color: white; } #cart table { border-top: 1px dotted #595; border-bottom: 1px dotted #595; margin-bottom: 10px; }
<%= button_to 'Add to Cart', line_items_path(:product_id => product), :remote => true %>2、在控制器中定义返回格式为JS
# POST /line_items # POST /line_items.xml def create @cart = current_cart product = Product.find(params[:product_id]) @line_item = @cart.add_product(product.id) respond_to do |format| if @line_item.save format.html { redirect_to(store_url) } format.js format.xml { render :xml => @line_item, :status => :created, :location => @line_item } else format.html { render :action => "new" } format.xml { render :xml => @line_item.errors, :status => :unprocessable_entity } end end end在同一文件夹下定义与动作同名的JS文件create.js.rjs
page.replace_html('cart', render(@cart))这一步迭代的整体图解如下:
<%unless cart.line_items.empty?%> <div class="cart_title">Your Cart</div> <table> <%= render(cart.line_items) %> <tr class="total_line"> <td colspan="2">Total</td> <td class="total_cell"><%= number_to_currency(cart.total_price) %></td> </tr> </table> <%= button_to 'Empty cart', cart, :method => :delete, :confirm => 'Are you sure?' %> <%end%>这样做的缺点是购物车一旦非空,整个侧边栏都会重新显示,因此最好不要这样实现。
#app\views\line_items/create.js.rjs page.replace_html('cart', render(@cart)) page[:cart].visual_effect :blind_down if @cart.total_items == 1因为要判断购物车中在线商品总数,因此还需要在购物车模型层文件中添加方法total_items
#app\models\cart.rb def total_items line_items.sum(:quantity) end end接下来要做的工作就是将空的购物车隐藏起来
#app\views\layouts\application.html.erb <div id="cart" <% if @cart.line_items.empty? %> style="display: none" <% end %> > <%= render @cart %> </div>如上,将逻辑插入到视图标签中的写法并不太优雅,因此我们考虑使用帮助方法来实现。
<!-- app\views\layout\application.html.erb --> <%= hidden_div_if(@cart.line_items.empty?, :id => "cart") do %> <%= render @cart %> <% end %>hidden_div_if方法:
#app\helpers\application_helper.rb module ApplicationHelper def hidden_div_if(condition, attributes = {}, &block) if condition attributes["style"] = "display: none" end content_tag("div", attributes, &block) end end因为现在当我们清除购物车之后,购物车信息自动从侧边栏隐藏,因此提醒用户购物车已为空的闪存消息不再有用,将其删除。