上一节:Ruby on Rails实战–创建一个网上商店B前台
本节将向商店加入一个Ajax购物篮,使商店产品列表在不刷新的情况下更新显示购物篮信息
修改depot/app/controllers/store_controller.rb文件,如下:
def index
@products = Product.find_products_for_sale
@cart = find_cart #加入对@cart的定义
end
def add_to_cart
begin
@product = Product.find(params[:id])
rescue
logger.error("Attempt to access invalid product #{params[:id]}")
redirect_to_index("Invalid product")
else
@cart = find_cart
@current_item = @cart.add_product(@product)
redirect_to_index unless request.xhr?
#request.xhr判断是否xmlHttpRequest, 否将指向index action, 用来兼容关闭了javascript功能的浏览器
#开发时以无Ajax的为蓝本,再修改到ajax,以方便兼容性处理
end
end
#….
private
def redirect_to_index(msg = nil)
#msg = nil 指定msg的默认值, 如果msg没有说明, msg = nil.
flash[:notice] = msg if msg
#加入对无参数的支持
redirect_to :action => :index
end
#…
修改depot/app/models/cart.rb文件,如下:
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)
@items << current_item
end
current_item #新加,使返回修改商品
end
修改depot/app/controllers/store_controller.rb文件,如下:
def add_to_cart
begin
@product = Product.find(params[:id])
rescue
logger.error("Attempt to access invalid product #{params[:id]}")
redirect_to_index("Invalid product")
else
@cart = find_cart
@current_item = @cart.add_product(@product) #新加,定义@current_item
end
end
#….
def empty_cart
session[:cart] = nil
redirect_to_index #清空购物篮后返回商品列表
end
#…
修改depot/app/models/cart.rb文件,增加一个购物篮内商品数据变量
def total_items
@items.inject(0) {|sum, item| sum + item.quantity}
end
在depot/app/views/store/index.rhtml
中将:
<%= button_to "Add to Cart", :action => :add_to_cart, :id => product %>
改为:
<%= form_remote_tag :url => { :action => :add_to_cart, :id => product } %>
<%= submit_tag "Add to Cart" %>
<%= end_form_tag %>
在depot/app/views/layouts/store.rhtml文件里加入模板对javascript的支持,如下:
<html>
<head>
<title>Pragprog Books Online Store</title>
<%= stylesheet_link_tag "depot", :media => "all" %>
<%= javascript_include_tag :defaults %>
</head>
在depot/app/views/store/新加一个partial template _cart.rhtml,内容如下:
<div class="cart-title">Your Cart</div>
<table>
<%= render(:partial => "cart_item", :collection => cart.items) %>
<!–调用另一个partial template _cart_item.rhtml–>
<tr class="total-line">
<td colspan="2">Total</td>
<td class="total-cell"><%= format_price(cart.total_price) %></td>
</tr>
</table>
<%= button_to "Empty cart", :action => :empty_cart %>
partial template以下找线开头,由render的调用.
在depot/app/views/store/新加一个partial template _cart_item.rhtml,内容如下:
<% 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"><%= format_price(cart_item.price) %></td>
</tr>
在depot/app/views/layouts/store.rhtml文件中增加调用partial template的代码:
<div id="side">
<%= hidden_div_if(@cart.items.empty?, :id => "cart") %>
<!–hidden_div_if 这个 helpper method用来向div加入display:none属性, 代码见下文–>
<%= render(:partial =>"cart", :object => @cart) %>
</div>
…..
创建hidden_div_if helpper method
def hidden_div_if(condition, attributes = {})
if condition
attributes["style"] = "display: none"
end
attrs = tag_options(attributes.stringify_keys)
"<div #{attrs}>"
end
删除不用了的add_to_cart.rhtml
新建depot/app/views/store/add_to_cart.rjs文件,内容如下:
page[:cart].replace_html :partial => ‘cart’, :object => @cart
#将页面中id=cart的元素换成partial _cart.rhtml的内容
page[:cart].visual_effect :blind_down if @cart.total_items == 1
#当向购物篮添加第一个商品时,特效显示出购物篮
page[:current_item].visual_effect :highlight,
:startcolor =>"#88ff88",
:endcolor =>"#114411"
#当购物篮商品发生变化时,特效显示变化行
本节完成,为使ajax效果生效, 我重新启动了服务器
下一节:Ruby on Rails实战–创建一个网上商店D收银台
本文最后更新 20070108
转载请注明: 转自船长日志, 本文链接地址: http://www.cslog.cn/Content/ruby_on_rails_ajax_eshop/