Agile Web Development with Rails 翻译(十)

Agile Web Development with Rails 翻译(十)

 

这就是为什么New products表单已经带有知道的titledescriptionimageprice字段因为它们在数据库表中,它们已经被添加到了“模型”中。通过“支架”表单“生成器”可以向“模型”要求有关这些字段的信息,然后就使用它找到的字段来创建个合适的HTML表单。

2006年4月16日更新


 

 

6.3 循环 A3: 确认!

 

经过两次的反复,我们的客户注意到,如果它输入一个无效的单价,或者忘记设置产品的描述信息,应用程序会接受这些并添加到数据库中。丢失产品的描述信息还只是个麻烦,但是单价若为零元则要损失金钱,所以客户要求我们添加对应用程序的确认工作。如果产品的文本字段为空,或一个无效图片的URL,或无效的单价,它们则不应该被存到数据库中。

但是,我们把确认放在哪里呢?

“模型”层是代码与数据库之间的守护者。我们的应用程序访问数据库时没做任何事,或者将数据存回到数据库时也没有通过“模型”。那么就把所有的确认工作放在这里;不管数据的流向如何都不会有问题。如果在写到数据库之前,“模型”检查它,就可以阻止损坏的数据到数据库中。

让我们看看“模型”类的源代码(app/models/product.rb)

class Product < ActiveRecord::Base

end

这什么也没有?当然,所有重体力活(数据库映射,创建,更新,搜索,等等)都被父类(ActiveRecor::BaseRails的一部分)完成了。由于继承的关系,我们的Product类自然地继承了所有功能。

添加我们的确认应该很容易。让我们通过确认所有写到数据库内文本字段开始。我们只是添加一些代码到现有的“模型”内。

class Product < ActiveRecord::Base

validates_presence_of :title, :description, :image_url

 

end

validates_presence_of()方法是个标准的Rails确认器。它检查给定的字段,或设置字段,以及它们内容是否为空。图6.6显示了如果你试着提交一个没有填充完字段的产品时,会发生什么事。给人印象是:有错误的字段被高亮度显示,然后错误被总结出来放到顶部的表单内。没有用于错误的代码。你也可能注意到,在编辑完product.rb文件后你并没有重启动应用程序来测试你的修改在开发模式中,Rails会注意到被修改的文件并重新加载它到应用程序中。这是促进开发的重大生产力。

 

 

现在我们想确认单价是否是有效的正整数。我们分再步解决这个问题。首先,我们使用validates_numericality_of()方法来确认单价是否是有效的数字。

validates_numericality_of :price

 

现在如果我们用无效的单价添加产品时,就会出现相应的消息。[MySQLRails足够的元数据使它知道单价包含了数字,所以Rails转换它到个浮点值。对于其它数据库,这个值可能是字符串支持的,所以在用于比较之前,你需要使用Float(price)来转换它。]

 

 

 

接着我们要检查它是否大于零。在我们的“模型”类中,我们可写个方法validate()来做这件事。Rails在保存我们产品的实例之前会自动地调用这个方法。所以我们可以用它检查字段的效性。我们将这个方法设置为protected,因为它不应该从“模型”的上下文环境的外部被调用。

protected

def validate

errors.add(:price, "should be positive") unless price.nil? || price > 0.0

end

如果单价小于或等于零,validation方法使用errors.add(…)来记录这个错误。这样做会阻止Rails写入错误数据到数据库中。它也显示了友好的信息给用户。传递给errors.add()的第一个参数是字段的名字,第二个参数是消息的内容。注意,我们只检查了单价的设置。如果没有这些额外的设置我们就不能比较nil0.0,并且会引发一个异常。

用于确认的另外两件事是:首先我们想确保每个产品有个唯一的标题。在“模型”的Product内有行代码可完成这件事。唯一性确认使用个简单的检查来确保,products表内没有与我们要保存的这个产品同名的行。

validates_uniqueness_of :title

 

最后,我们需要确认输入的图像URL的有效性。我们使用validates_format_of()方法来做,它用正则表达式来匹配一个字段。现在我们只检查URLhttp:开始部分,以及是否以.gif.jpg.png结尾。[稍后,我们或许想修改这个形式以让用户从一个有效的images列表中选择一个,但是们还想保持对一些有恶意的人提供数据的确认。]

validates_format_of :image_url,

:with => %r{^http:.+.(gif|jpg|png)$}i,

:message => "must be a URL for a GIF, JPG, or PNG image"

到现在,我们已经添加了这些用于检查的确认

1、字段titledescription,和image URL是否为空。

2price是否是大于零的有效数字。

3title是否是唯一名字。

4image URL看起来是否合理。

这是“模型”内的Product类更新后的完整列表。

class Product < ActiveRecord::Base

validates_presence_of :title, :description, :image_url

validates_numericality_of :price

validates_uniqueness_of :title

validates_format_of :image_url,

:with => %r{^http:.+.(gif|jpg|png)$}i,

:message => "must be a URL for a GIF, JPG, or PNG image"

protected

def validate

errors.add(:price, "should be positive") unless price.nil? || price > 0.0

end

end

在接近尾声时,我们要求我们客户在用次应用程序,它很高兴。它只看了几分钟,但简单的确认动作会让产品管理页面感觉很牢固了。

 

“控制器”处理来自浏览器的“请求”。一个应用程序可以有多个“控制器”。对于我们的Depot应用程序来说,我们最终会有二个“控制器”,一个用于处理卖方的站点管理,另一用于处理买方。我们在Admin“控制器”内创建产品维护的“支架”,这就是为什么在URLadmin是它的第一个路径部分。

这个工具生成的Rails “支架”使用Ruby代码来组装你的应用程序目录树。如果你检查它,你会现有个完整的应用程序构架其内已经放置了Ruby代码;这些都是源代码,而不是简单地对一些标准库的调用。对我们来说,这是个好消息,因为它意味着我们可以修改“支架”内产生的代码。“支架”是一个应用程序的起点,而不应用程序的终点。

 

-------------------------------------------------------------------

David . . .

我们能更换所有的“支架”吗?

 

大多数是这样的。“支架”不是应用程序开发的目的。它只是在我们构建应用程序时提供支持。当你设计出产品的列表该如何工作时,你依赖于“支架”“生成器”产生创建,更新,和删除的行为。然后在保留这个“动作”时你要替换由“生成器”生成的行为。有时候当你需要一个快速接口时,并且你并不在乎界面的丑陋,“支架”就足够用了。不要指望“支架”能满足你程序的所有需要。

-------------------------------------------------------------------

 

6.2 循环 A2: 添加被遗漏的列

 

我们展示基于“支架”的代码给们的客户,并解释这还很粗糙。它们会很高兴这么快就看到一些东西可以工作了。当客户试用一会之后,它会注意到我们最初的讨论中有些东西被遗漏了。查看显示在浏览器窗口内的产品信息,很明显需要我们添加个日期列过期的产品不应该给消费者。

这就意味着们要添加一列到数据库表中,并且我们还要确保不同的管理页面都要被更新并支持这个新列。

一些开发者(DBA)可能会这样做:

alter table products

add column date_available datetime;

相反,我倾向于维护一个我最初用来创建的,包含DDL的文本文件。这样我会有历史记录,并在一个单个文件包含我需要重新创建的所有命令。所以让们选择文件db/create.sql,并添加date_available列。

drop table if exists products;

 

create table products (

id int not null auto_increment,

title varchar(100) not null,

description text not null,

image_url varchar(200) not null,

price decimal(10,2) not null,

date_available datetime not null,

 

primary key (id)

);

当我第一次创建这个文件时,我添加一个drop表命令在它的顶端。现在这允许我们在命令行创建一个新(空的)计划实例。

depot> mysql depot_development <db/create.sql

很明显,这种方式只对现有数据库内的表没重要数据才可行。在开发期间这没问题,但在发行产品中我们需要更小心些。一旦一个应用程序被发行,我们会移走我们数据库计划脚本。

即使在这期间,这也是个痛苦,因为我们需要重新输入我们测试数据。通常我在开发期间若输入了些数据的话,我会从数据库中转储它们,然后在我每次执行计划时再重新加载它们。

计划已经更改了,所以我们“支架”代码就变得过时了。因为我还没有修改这些代码,所以可以安全地重新产生它。注意当“生成器”脚本覆写一个文件时,它会提示我们。我们输入指令a来允许它覆写所有文件。

depot> ruby script/generate scaffold Product Admin

 

dependency model

exists app/models/

exists test/unit/

exists test/fixtures/

skip app/models/product.rb

skip test/unit/product_test.rb

skip test/fixtures/products.yml

exists app/controllers/

exists app/helpers/

exists app/views/admin

exists test/functional/

overwrite app/controllers/admin_controller.rb? [Ynaq] a

 

forcing scaffold

force app/controllers/admin_controller.rb

force test/functional/admin_controller_test.rb

force app/helpers/admin_helper.rb

force app/views/layouts/admin.rhtml

force public/stylesheets/scaffold.css

force app/views/admin/list.rhtml

force app/views/admin/show.rhtml

force app/views/admin/new.rhtml

force app/views/admin/edit.rhtml

create app/views/admin/_form.rhtml

 

 

 

刷新浏览器,并创建个新产品,你会看到像图6.5样的东西。(如果不一样的话,可能“生成器”还在等着你输入a)现在我们有了date字段,这是反馈信息的功劳。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值