`
waveeee
  • 浏览: 50868 次
  • 来自: 上海
社区版块
存档分类
最新评论

agile rails depot 4

    博客分类:
  • ruby
阅读更多
appointment: this demo ran in ubuntu, and Rails 2.2.2
the 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 this
depot_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.rb
def index
  @products = Product.find_products_for_sale
  @cart = find_cart
end


redirect the browser back to the index:
  app/controllers/store_controller.rb
def add_to_cart
product = Product.find(params[:id])
@cart = find_cart
@cart.add_product(product)
redirect_to_index
rescue ActiveRecord::RecordNotFound
logger.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 msg
redirect_to :action => 'index'
end


add two method in models/cart.rb
 def total_price
    @items.sum { |item| item.price }
  end

  def 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_cart
product = Product.find(params[:id])
@cart = find_cart
@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


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_item
end  

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.rjs
page.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.rb
def 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.rb
module StoreHelper
def hidden_div_if(condition, attributes = {}, &block)
if condition
attributes["style" ] = "display: none"
end
content_tag("div" , attributes, &block)
end
end























分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics