Agile Web Development with Rails 翻译(二十)
Agile Web Development with Rails 翻译(二十)
第十章 任务 E:购物
我们现在已处于这样的时刻,买方可以使用我们的应用程序来产生定单。我们的客户很想看看它是如何满足这些订单的。
现在,在一个完全开发好的商店应用程序中,满足订单将是一个非常巨大而复杂的处理。我们需要和各种各样的后台送货机构集成,我们需要产生用户反馈信息,我们也可能需要连接到一些结帐终端。我们不打算在这里做这些。但是尽管我们准备保持简单,我们仍然有机会体验partial layouts,集合和一种稍稍不同于我们迄今使用的交互方式。
10.1 Iteration E1: 基本购物
关于发货功能我们和客户聊了一会儿。她说,她想看到一个还未发货的订单清单。一个发货员将检查该清单,并手动地处理一个或多个订单。一旦订单被发货,发货员将在系统中标记它们,它们将再也不会出现在发货页面。
我们的第一个任务是找出如何指示一个订单是否已经被发货。很显然我们需要在orders表中定义一个新列。我们可以定义它为一个简单的字符列(也许"Y"意味着发货,"N"意味着没有),但是我倾向于使用时间戳来处理这类事情。如果该列有一个null值,该订单未发货,否则,该列的值就是发货的日期和时间。用这样的方法,该列不仅告诉我们订单是否被发货,还能告诉我们是何时被发货的。
因此,让我们修改db目录中的create.sql文件,给orders表增加shipped_at列.
-------------------------------------------------------
David 说. . .
日期与时间戳列名字
Rails列名字约定指出:datetime字段应该以_at结尾,date字段应该以_on结尾。以这种自然的方式对列命名,如last_edited_on 和 sent_at。
这种约定也用于自动的时间戳字段,在267页描述,例如created_at会由Rails自动填充。
----------------------------------------------------------
create table orders (
id int not null auto_increment,
name varchar(100) not null,
email varchar(255) not null,
address text not null,
pay_type char(10) not null,
shipped_at datetime null,
primary key (id)
);
我们加载这个新计划。
depot> mysql depot_development <db/create.sql
为了保存我们每次重载计划时在管理页面输入的产品数据,我也想乘这个机会来写一个简单SQL语句集来载入产品表。它很简单,如下所示:
lock tables products write;
insert into products values(null,
'Pragmatic Project Automation', #title
'A really great read!', #description
'/images/pic1.jpg', #image_url
'29.95', #price
'2004-12-25 05:00:00'); #date_available
insert into products values('',
'Pragmatic Version Control',
'A really controlled read!',
'/images/pic2.jpg',
'29.95',
'2004-12-25 05:00:00');
unlock tables;
然后载入数据库。
depot> mysql depot_development <db/product_data.sql
我们回到我们应用程序的管理部分,现在我们需要在admin_controller.rb文件中创建一个新的action。让我们称之为ship()。我们知道它的目的是获得等待发货的订单清单以便view去显示它。那么让我们用这样的思路编码,看看会怎么样:
def ship
@pending_orders = Order.pending_shipping
end
我们现在需要在order model中实现pending_shipping()类方法,它返回所有shipped_at列为null的订单。
def self.pending_shipping
find(:all, :conditions => "shipped_at is null")
end
最后,我们需要一个view来显示这些订单。view必须含有一个表单,因为每个订单会和一个检查框联系在一起(一旦定单被发货,则发货员会设置它)。在表单里,我们将为每个订单定义一个条目。我们可以给view中每个条目包含所有的layout代码,但是正如我们将复杂的代码变为方法那样,让我们将view分为两个部分:全局表单和在表单中被提交的每个订单的部分。这类似于在代码中有一个循环,每次循环调用一个方法来做一些处理。
当我们在checkout页面用component来显示购物车内容时,我们已经看到了在view级别处理类似子程序的方法。一个做同样工作的轻量级的方法是使用一个局部模板。不同于基于基于组件的方法,一个局部模板没有对应的动作;它仅是被包含在一个独立文件中的一组模板代码。
让我们在目录app/views/admin中创建全局的ship.rhtml view。
Line 1 <h1>Orders To Be Shipped</h1>
-
- <%= form_tag(:action => "ship") %>
-
5 <table cellpadding="5" cellspacing="0">
- <%= render(:partial => "order_line", :collection => @pending_orders) %>
- </table>
-
- <br />
10 <input type="submit" value=" SHIP CHECKED ITEMS " />
-
- <%= end_form_tag %>
- <br />
注意第6行的render()调用。:cellection参数是我们在action方法内创建的订单的清单。:partial参数完成双重任务。
"order_line"的第一个用途是识别要提交的局部模板的名字。这是一个view,因此它和其他view一样是.rhtml文件。可是,由于局部的特别性,你在它的文件名中以下划线开头来命名它。在本例中,Rails将会在app/views/admin/_order_line.rhtml文件内寻找局部模板。
"order_line" 参数同时告诉Rails设置局部变量order_line的值为当前被提交的order。该变量仅在局部模板中有效。对于订单集合的每次迭代,order_line将更新集合内对下个order的引用。
在掌握了所有这些知识后,我们现在可以写出这个局部模板,_order_line.rhtml了。
<tr valign="top">
<td class="olnamebox">
<div class="olname"><%= h(order_line.name) %></div>
<div class="oladdress"><%= h(order_line.address) %></div>
</td>
<td class="olitembox">
<% order_line.line_items.each do |li| %>
<div class="olitem">
<span class="olitemqty"><%= li.quantity %></span>
<span class="olitemtitle"><%= li.product.title %></span>
</div>
<% end %>
</td>
<td>
<%= check_box("to_be_shipped", order_line.id, {}, "yes", "no") %>
</td>
</tr>
现在,使用应用程序的store部分,创建一些订单,然后切换到localhost:3000/admin/ship。你将看到如图10.1所示。它工作了,但样子不是很好看。在应用程序的store部分,我们使用了一个layout来给所有页面做框架,并应用了一个通用的样式表。在我们进一步开发以前,让我们在这里做同样的事。实际上Rails已经创建了layout(当我们第一次生成admin scaffold时)。让我们来美化它。编辑app/views/layouts目录中的admin.rhtml。
<html>
<head>
<title>ADMINISTER Pragprog Books Online Store</title>
<%= stylesheet_link_tag "scaffold", "depot", "admin", :media => "all" %>
</head>
<body>
<div id="banner">
<%= @page_title || "Administer Bookshelf" %>
</div>
<div id="columns">
<div id="side">
<%= link_to("Products", :action => "list") %>
<%= link_to("Shipping", :action => "ship") %>
</div>
<div id="main">
<% if @flash[:notice] -%>
<div id="notice"><%= @flash[:notice] %></div>
<% end -%>
<%= @content_for_layout %>
</div>
</div>
</body>
</html>

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号