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>

posted @ 2007-02-17 10:22  海浪~~  阅读(179)  评论(0)    收藏  举报