- 浏览: 32361 次
- 性别:
- 来自: 福建
文章分类
最新评论
Chapter 11. Task F. Add a Dash of Ajax
6.1 使用partial重构Cart:
partial(局部)模板简称:partials.可以在其他的模板或Controller中调用(呈现)这个局部模板.
那么在调用的地方,局部模板就可以呈现出数据.
你也可以传递参数给局部模板就像传递参数给方法一样来得到不同的呈现结果(传递了Collection).
The partial template itself is simply another template file (by default in the same directory
as the object being rendered and with the name of the table as the name).
局部模板默认所在的视图目录是 和模板里要呈现的对象(line_item)的相同目录下(views/line_items/).
局部模板的文件名默认是render括号里的(最终)参数,如果是对象关联,则采用单数形式.???
Inside the partial template, we refer to the current object using the variable name that
matches the name of the template. _line_item.html.erb对应的模板为line_item(:去掉文件名头的_)
所以在局部模板里,使用和模板名字相同的变量即line_item.
-> app/views/carts/show.html.erb <% @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 %> 替换为: <%= render(@cart.line_items) %> -> app/views/line_items/_line_item.html.erb <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>
6.2 继续重构partial,传递实例变量给render:
move the cart into the sidebar.If we had a partial template that could display the cart,
we could simply embed a call like this within the sidebar: render("cart")
In the layout(views/carts/show.html.erb), we have access to the @cart instance variable
that was set by the controller. And this is also available inside partials called from the layout.
在show.html.erb这个Layout中可以使用在Controller中设置的实例变量@cart.在partials中同样可以使用实例变量.
既然render可以跟上Collection参数:render(@cart.line_items) 当然也可以只跟上参数render @cart.
不同的是传递@cart.line_items参数,在partial(_line_item)中不需要再循环.
而传递@cart参数,则在partial(_cart)中需要根据cart取得对应的line_items.
和_line_item.html.erb中使用变量line_item一样.这里_cart.html.erb也是使用cart变量.
-> app/views/carts/show.html.erb <%= render @cart %> views/carts/show.html.erb只有一行代码. render跟上的参数是实例变量@cart -> app/views/carts/_cart.html.erb <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?' %>
6.3 把Cart购物车信息呈现在sidebar:
局部模板可以在任何地方引用,所以如果要在主页面(localhost:3000)的sidebar上显示局部模板的内容
同时要在对应的Controller(StoreController)中定义对应的实例变量(@cart).
正如在carts/show.html.erb中能够使用@cart是因为line_items_controller.rb的create方法中定义了@cart变量
在redirect_to @line_item.cart即carts/show...中就能使用该变量(为什么重定向到show见前面的分析).
改变控制流:之前是点击Product的购买按钮(即每创建一个LineItem到购物车中),就转到购物车页面(carts/show).
如果这时返回到localhost:3000 就会在主页面的sidebar上同样能看到购物车信息.
而我们想要在点击购买时不跳转到购物车页面, 而是直接在原来的页面的sidebar上显示购物车信息.
-> app/views/layouts/application.html.erb <div id="cart"> <%= render @cart %> </div> -> app/controllers/store_controller.rb class StoreController < ApplicationController def index @products = Product.all @cart = current_cart end end -> app/controllers/line_items_controller.rb if @line_item.save #format.html{ redirect_to @line_item.cart} format.html { redirect_to(store_url) }
When we click to add an item to the cart, the page is redisplayed with an updated cart.
重定向到主页面是整个页面都刷新,而变化的只是partial中的内容.其他内容一般是不会变化的.Ajax Coming!
6.4 购买按钮发送Ajax请求,应用程序使用RJS模板呈现内容:
change the catalog page to send an Ajax to our server application
button_to:create the link to the create action.加上:remote参数表示现在发送的是一个Ajax请求.
改变页面向服务器端应用程序发起一个Ajax请求,
have the application respond with the HTML fragment containing the updated cart.
create the updated HTML fragment that represents the cart
to have the browser stick that HTML into the browser’s internal representation of DOM being displayed.
应用程序响应,并应答一段HTML代码(展示了最新的购物车).
创建一段HTML代码来代表购物,然后让浏览器把这段代码插入到当前页面的DOM,替换掉当前页面显示的购物车.
when create finishes handling the Ajax request, Rails will look for a create template to render
当在create方法中处理完Ajax请求(点击购买,调用create方法,line_item.save成功)
根据format.js,Rails会去寻找对应的模板来呈现内容:create.js.rjs.
正如format.html(后面没有加上redirect_to).默认对应的是方法名.文件后缀.比如new方法:format.html->new.html.erb
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. rjs模板允许你能够在浏览器上得到JS代码即:将JavaScript发送到浏览器.
-> app/views/store/index.html.erb <%= button_to 'Add to Cart', line_items_path(:product_id => product), :remote => true %> -> app/controllers/line_items_controller.rb def create respond_to do |format| if @line_item.save format.html { redirect_to(store_url) } format.js end end end -> app/views/line_items/create.js.rjs page.replace_html('cart', render(@cart))
The page variable is an instance of JavaScript generator-a Rails class that knows
how to create JavaScript on the server and have it executed by the browser.
Rails提供的JavaScript(帮助类,application Layout中包含库:<%= javascript_include_tag :defaults %>)
生成器类的实例变量page,能够在服务器端创建JS,并使其在浏览器上运行.
replace the content of the element on the current page with the id cart with the rendered partial for a given cart.
This simple RJS template then tells the browser to replace the content of the element whose id="cart" with that HTML.
将当前页面id为cart的元素替换成render @cart的内容(局部模板里的内容就是最新的购物车的内容).
调试Ajax程序:
查看development.log是否有报错;或者是否有请求调用到create方法.若没有说明浏览器没有发起Ajax请求.
查看页面源文件检查JS库是否加载到浏览器; 浏览器缓存; 针对IE的头信息:<!DOCTYPE html>
6.5 高亮显示最近更新的购物项:
identifying the most recently updated item in the cart.
pass the current line item down to the template(create.js.rjs) by assigning it to an instance variable
标识购物车中最近更新的购物项. Ajax请求处理完后(在format.js后添加)将当前购物项作为实例变量返回.
In the _line_item.html.erb partial, we then check to see whether the item we’re rendering is
the one that just changed. If so, we tag it with an id of current_item:
在购物项局部模板中(因为最终显示的购物项内容其实是在_line_item局部模板里)而不是在application或者carts/show中.
在Controller的Action#create(添加完购物项保存成功)设置的实例变量,在局部模板里仍然是可以访问到的@current_item.
在_cart局部模板里render cart.line_items循环购物的每个购物项,如果当前循环到的购物项=实例变量里保存的变量
@current_item 则把这个购物项标记一个id:<tr id="current_item">.最后只要把黄渐变的效果运用到这个元素上即可.
now the <tr> element of the most recently changed item in the cart will be tagged with id="current_item".
identified the browser element that apply the effect to by passing :current_item to the page.
-> app/controllers/line_items_controller.rb def create if @line_item.save format.html { redirect_to(store_url) } format.js { @current_item = @line_item } -> app/views/line_items/_line_item.html.erb <% if line_item == @current_item %> <tr id="current_item"> <% else %> <tr> <% end %> <td><%= line_item.quantity %>×</td> <td><%= line_item.product.title %></td> <td class="item_price"><%= number_to_currency(line_item.total_price) %></td> </tr> -> app/views/line_items/create.js.rjs page[:current_item].visual_effect :highlight, :startcolor => "#88ff88", :endcolor => "#114411"
6.6 隐藏空购物项:
当购物车为空时,<div id="cart" style="display:none">不显示购物车.
-> app/views/line_items/create.js.rjs #采用Ajax将最近更新的购物项替换原来的购物车 page.replace_html('cart', render(@cart)) #如果购物车中有了一项购物项,则在边框就应该显示购物车. page[:cart].visual_effect :blind_down if @cart.total_items == 1 #高亮显示最近更新的购物项 page[:current_item].visual_effect :highlight, :startcolor => "#88ff88", :endcolor => "#114411" -> app/models/cart.rb #6种写法: 成员变量前@ 数组.to_a 用Symbol:代替临时变量 def total_price line_items.to_a.sum {|item| item.total_price} #@line_items.to_a.sum {|item| item.total_price} #@line_items.sum {|item| item.total_price} #line_items.sum {|item| item.total_price} #@line_items.sum(:total_price) #line_items.sum(:total_price) end def total_items #购物车所有购物项的所有数量.比如购物项1 数量2 购物项2 数量3 则只为5 line_items.sum(:quantity) #line_items.sum{ |item| item.quantity } end -> app/views/layouts/application.html.erb <div id="cart" <% if @cart.line_items.empty? %>style="display:none"<% end %> > <%= render(@cart) %> </div>
using Ajax to add products to the cart, the main page doesn’t get redrawn
between requests as people shop. we’ll continue to display the flash message
saying the cart is empty even as we display a cart in the sidebar.
清空购物车时,不需要显示flash消息. 否则如果再次往购物车中添加Product,因为采用了Ajax
只刷新了局部模板,没有刷新整个页面,导致flash消息仍然停留在主页面上,造成困惑.
-> app/controllers/carts_controller.rb def destroy #format.html { redirect_to(store_url, :notice => 'Your cart is currently empty') } format.html { redirect_to(store_url) }
abstract some processing out of a view (any kind of view),write a helper method.
当需要将处理逻辑从视图(partial,rjs模板)中抽象出来,可以编写辅助方法.
6.7 抽象视图中的处理逻辑:
It take a condition, an optional set of attributes, and a block.
if the condition is true,adding the display: none style.
It wraps the output(content_tag) generated by the block in a <div> tag. [wraps output]
把(传递给它:content_tag的)代码块的输出用标记(div)包装起来.如条件为真,则(div)加上style样式
By using the &block notation, we get Ruby to pass the block that was given to hidden_div_if
down to content_tag. [pass block down to content_tag]
通过&block标志,将代码块经过hidden_div_if()传递给content_tag(). 有点类似回调函数.参数继续传递.
-> 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 -> app/views/layouts/application.html.erb <%= hidden_div_if(@cart.line_items.empty?, :id => "cart") do %> <%= render @cart %> <% end %>
make the cart hide and reveal itself
by making the CSS display style conditional on the number of items in the cart.
used an RJS template to invoke the blind_down effect when the cart went from being empty to having one item.
显示和隐藏购物车: 根据Cart中购物项的数量设置CSS样式;当第一件Product被放进购物车时,通过RJS模板调用效果.
6.8 测试采用Ajax引起的问题:
> rake test
或者访问http://localhost:3000/products报错:NoMethodError in Products#index
where line #17 raised: <%= hidden_div_if(@cart.line_items.empty?, :id => "cart") do %>
如果把store_controller.rb的@cart = current_cart注释掉.同样报错:NoMethodError in Store#index
where line #17 raised:<%= hidden_div_if(@cart.line_items.empty?, :id => "cart") do %>
这就是我们前面说到的.如果Controller中没有定义变量@cart,在视图中使用就无法使用相应的变量(6.3).
@cart is apparently nil when we display an index of our products.it is set only in the store controller.
avoid displaying the cart at all unless this value is set:
-> app/views/layouts/application.html.erb <% if @cart %> <%= hidden_div_if(@cart.line_items.empty?, :id => "cart") do %> <%= render @cart %> <% end %> <% end %> -> test/functional/line_items_controller_test.rb test "should create line_item" do assert_difference('LineItem.count') do #post :create, line_item: @line_item.attributes post :create, :product_id => products(:ruby).id end #assert_redirected_to line_item_path(assigns(:line_item)) #assert_redirected_to cart_path(assigns(:line_item).cart) assert_redirected_to store_path end test "should create line_item via ajax" do assert_difference('LineItem.count') do xhr :post, :create, :product_id => products(:ruby).id end #Instead of a redirect,we expect a successful response assert_response :success #containing a call to replace the HTML for the cart #extract the relevant HTML and then processing that HTML via whatever additional assertions you want to apply assert_select_rjs :replace_html, 'cart' do #find a row with an id of current_item with a value matching Programming Ruby 1.9 assert_select 'tr#current_item td', /Programming Ruby 1.9/ end end
相关推荐
在《Agile Web Development with Rails》中,读者可以学习到如何运用敏捷方法来规划项目,实施增量式开发,并通过频繁的反馈来提高产品质量。 Ruby on Rails(简称Rails)是一个基于Ruby语言的开源Web开发框架,它...
Ruby on Rails helps you produce high-quality, beautiful-looking web applications quickly. You concentrate on creating the application, and Rails takes care of the details., Tens of thousands of ...
《Agile Web Development with Rails》(敏捷Web开发:Ruby on Rails)这本书,作为Rails开发新手的教材,强调了敏捷开发方法,并以其帮助开发者建立起一个实用的Web应用。从给出的文件信息来看,这本书正在编写过程...
Agile Web Development with Rails 1-14节_ppt(老师发的修正版)
agile web development with rails 5(英文电子书).............................................................................................................................................................
《敏捷Web开发与Rails》是一本深度探讨如何利用Ruby on Rails框架进行敏捷Web开发的指导书籍,由Dave Thomas、David Heinemeier Hansson等多位在Rails社区有着深厚贡献的作者共同编写。本书不仅覆盖了Rails的基本...
### 敏捷Web开发与Rails 3:关键知识点解析 #### 一、Rails版本与兼容性 本书《敏捷Web开发与Rails》第三版是基于Rails 2编写的。截至本书印刷时,当前可用的Rails Gem版本为2.1。书中所包含的所有代码均已在该...
《敏捷Web开发与Rails:程序指南 第四版》是一本深度探讨使用Ruby on Rails框架进行敏捷Web应用开发的专业书籍。本书旨在帮助开发者充分利用Rails 4的特性,提高开发效率,实现快速迭代和高质量的代码编写。 Rails是...
总而言之,《敏捷Web开发与Rails》第四版是一本全面覆盖Rails 3的教程,它不仅教授了Rails框架的基础知识,还深入探讨了敏捷开发的最佳实践,对于任何想要掌握或提升Rails技能的人来说,都是一本不可或缺的参考资料...
在学习这两本书时,你可以从Pragmatic Programmer - Agile Web Development With Ruby On Rails_05.12.24.pdf和Pragmatic.Bookshelf.Agile.Web.Development.with.Rails.2nd.Edition.pdf中获取详细教程。这些PDF文件...
《Pragmatic - Agile Web Development with Rails》是Ruby on Rails框架的经典教材,旨在引导初学者高效地学习敏捷Web开发。这本书的第三版于2009年发布,它结合了Pragmatic Programmers的实用主义理念与Ruby on ...
Agile Web Development with Rails, 2nd Edition <br>有两份PDF文件,大小分别是7.39MB和6.55MB <br>作者: Dave Thomas , David Heinemeier Hansson , Leon Breedt , Mike Clark , James Duncan Davidson ,...
### Agile Web Development with Rails for Rails 3.2 #### 核心知识点概览 - **Rails 3.2概述** - **敏捷开发方法论** - **Model-View-Controller (MVC) 模式** - **Ruby on Rails基础与高级特性** - **面向对象...
Agile Web Development with Rails 4th(正式版).pdf
### Agile Web Development with Rails 第四版 #### 书籍概述与价值 《Agile Web Development with Rails》第四版是一本经典的Rails开发指南,旨在为开发者提供一套全面、实用且高效的敏捷开发方法论。本书由Sam ...