agile rails depot 4
appointment: this demo ran in ubuntu, and Rails 2.2.2the demo comes from agile web development with rails 3
script>>some linux script
mysql>some db command
---------------------------------------------------------
Add a Dash of Ajax
---------------------------------------------------------
step 1
u can think of rails partial templates as a kind of method for views.
a partial is simply a chunk of view in its own separate file. u can invoke(render)
a partial from another template or from a controller, and the partial will render
itself and return the result of that rendering
views/store/add_to_cart.html.erb
<%= render(:partial => "cart_item" , :collection => @cart.items) %>
views/store/_cart_item.html.erb
views/store/_cart.html.erb
<%= render(:partial => "cart_item" , :collection => cart.items) %>
views/layouts/store.html.erb
<div id="cart"><%= render(:partial => "cart" , :object => @cart) %></div>
Coding list like thisdepot_j/app/views/store/add_to_cart.html.erb<div class="cart-title">Your Cart</div><table><%= 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><%= button_to "Empty cart" , :action => :empty_cart %>app/views/store/_cart_item.html.erb<tr><td><%= cart_item.quantity %>&times;</td><td><%=h cart_item.title %></td><td class="item-price"><%= number_to_currency(cart_item.price) %></td></tr>app/views/store/_cart.html.erb<div class="cart-title">Your Cart</div><table><%= 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><%= button_to "Empty cart" , :action => :empty_cart %>app/views/layouts/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" %></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(: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"><% if flash[:notice] -%><div id="notice"><%= flash[:notice] %></div><% end -%><%= yield :layout %></div></div></body></html>
We’re invoking the layout while looking at the store’s index action, and that action doesn't currently set @cart. That’s easy enough to remedy:
app/controllers/store_controller.rbdef index@products = Product.find_products_for_sale@cart = find_cartend
redirect the browser back to the index:
app/controllers/store_controller.rb
def add_to_cartproduct = Product.find(params[:id])@cart = find_cart@cart.add_product(product)redirect_to_indexrescue ActiveRecord::RecordNotFoundlogger.error("Attempt to access invalid product #{params[:id]}" )redirect_to_index("Invalid product" )end
app/controllers/store_controller.rb
def redirect_to_index(msg = nil)flash[:notice] = msg if msgredirect_to :action => 'index'end
add two method in models/cart.rb
def total_price @items.sum { |item| item.price }enddef total_items @items.sum { |item| item.quantity }end
step 2
create an ajax-based cart
1. use form_remote_tag to create a remote procedure call to ur application.
chang>> views/store/index.html.erb
<%= button_to "Add to Cart" , :action => :add_to_cart, :id => product %>
to >>
<% form_remote_tag :url => { :action => 'add_to_cart', :id => product } do %><%= submit_tag "Add to Cart" %><% end %>
2. add a call to javascript_inlude_tag to the <head> section of the store layout:
views/layouts/store.html.erb
<head><title>Pragprog Books Online Store</title><%= stylesheet_link_tag "depot" , :media => "all" %><%= javascript_include_tag :defaults %></head>
3. change response to the controllers to add_to_cart
def add_to_cartproduct = Product.find(params[:id])@cart = find_cart@cart.add_product(product)respond_to do |format|format.jsendrescue ActiveRecord::RecordNotFoundlogger.error("Attempt to access invalid product #{params[:id]}" )redirect_to_index("Invalid product" )end
4. rails supports RJS templates-- the JS stands for JavaScript. A .js.rjs template is a way of getting JavaScript on the browser to do what you want, all by writing server-side ruby code.Let's write our first: add_to_cart.js.rjs
.
app/views/store/add_to_cart.js.rjs
page.replace_html("cart" , :partial => "cart" , :object => @cart)
5. u mey need to delete the old add_to_cart.html.erb
step 3 hight-lighting changes
1. we need to know if the current_item changed.
/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_itemend
2. add controller response
/controllers/store_controller.rb
def add_to_cart product = Product.find(params[:id]) logger.error( product); @cart = find_cart @current_item = @cart.add_product(product) respond_to do |format| format.js end rescue ActiveRecord::RecordNotFound logger.error("Attempt to access invalid product #{params[:id]}" ) redirect_to_index( "Invalid product")end
3. identify changed current_item
<% if cart_item == @current_item %> <tr id="current_item"><% else %><tr><% end %><td><%= cart_item.quantity %>&times;</td><td><%=h cart_item.title %></td><td class="item-price"><%= number_to_currency(cart_item.price) %></td></tr>
4. add effect of the dynamic change content
views/store/add_to_cart.js.rjspage.replace_html("cart" , :partial => "cart" , :object => @cart)page[:current_item].visual_effect :highlight,:startcolor => "#88ff88"
step 3
hiding an Empty Cart. and this may redirect the page
<% unless cart.items.empty? %><div class="cart-title" >Your Cart</div><table><%= 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><%= button_to "Empty cart" , :action => :empty_cart %><% end %>
step 4
the ajax way
app/models/cart.rbdef total_items@items.sum { |item| item.quantity }end
layout
<div id="cart"<% if @cart.items.empty? %>style="display: none"<% end %>><%= render(:partial => "cart" , :object => @cart) %></div>
----------------------------------------------------
views/store/add_to_cart.js.rjs
page.replace_html("cart" , :partial => "cart" , :object => @cart)page[:cart].visual_effect :blind_down if @cart.total_items == 1
step 5
use Helper Method
for this view is not looks good, we can use helper method to divide some parts
<div id="cart"<% if @cart.items.empty? %>style="display: none"<% end %>><%= render(:partial => "cart" , :object => @cart) %></div>/app/views/layouts/store.html.erb<% hidden_div_if(@cart.items.empty?, :id => "cart" ) do %><%= render(:partial => "cart" , :object => @cart) %><% end %>app/helpers/store_helper.rbmodule StoreHelperdef hidden_div_if(condition, attributes = {}, &block)if conditionattributes["style" ] = "display: none"endcontent_tag("div" , attributes, &block)endend
页:
[1]