Rails_00007

  • 格式:pdf
  • 大小:1.08 MB
  • 文档页数:50

296第30章部署与生产订单项?实际上你确实可以调用它的size()方法,该方法会返回关联对象的数量。

这个方法会在数据库的子表上执行select count(*)查询,统计出与当前父记录存在外键关联的记录总数。

有效,而且可靠。

但是,如果你需要频繁地获知子记录的数量,每次执行这条SQL语句也可能成为一种负担。

ActiveRecord使用了一种叫做计数器缓存(counter caching)的技术,也许可以帮上忙。

在子模型对象的belongs_to声明中,你可以要求ActiveRecord维护关联子对象的数量。

这个计数值会被自动维护:如果你插入了一条子记录,父记录中的计数值会加1;如果你删除一条子记录,计数值会减1。

要激活这一特性,只需要两个简单的步骤。

首先,在子模型对象的belongs_to声明中加上:counter_cache选项。

e1/ar/counters.rbclass LineItem<ActiveRecord::Basebelongs_to:product,:counter_cache=>trueend然后,在父表(在这里就是products表)的定义中加上一个整型字段,它的名字应该是“子表名加上_count后缀”。

Download e1/ar/counters.rbcreate_table:products,:force=>true do|t|t.string:titlet.text:description#...t.integer:line_items_count,:default=>0end必须注意的是,该字段的初始值必须为0(或者你必须想别的办法,在创建父记录的同时将其设为0)。

如果没有这样做,不管有多少条子记录存在,你得到的计数值都将为空。

完成这两个步骤之后,你就会发现:父记录中的计数器字段会自动跟踪关联子记录的数量。

计数器缓存有一个问题:计数值是由集合对象来维护的,如果子对象都通过集合对象来添加,那么计数值将得以正常更新。

然而,你也可以直接设置子对象的连接属性,使之与父对象关联,此时计数器就不会更新。

下列代码展示了错误的建立关联方式。

在这里,我们手工将子对象和父对象关联起来。

可以看到,size()属性的值是错误的,直到我们强迫父对象刷新子对象集合之后它才得到正确的值。

e1/ar/counters.rbproduct=Product.create(:title=>"Programming Ruby",:description=>"...")line_item=LineItem.newline_item.product=productline_item.saveputs"In memory size=#{product.line_items.size}"#=>0puts"Refreshed size=#{product.line_items(:refresh).size}"#=>1正确的做法是将子对象插入到父对象的集合属性中。

e1/ar/counters.rbproduct=Product.create(:title=>"Programming Ruby",:description=>"...")product.line_items.createputs"In memory size=#{product.line_items.size}"#=>1puts"Refreshed size=#{product.line_items(:refresh).size}"#=>1这次不仅得到了正确的计数值,而且代码也更短,说明这的确是正确的做法。

1.1Rails是敏捷的297第20章ActiveRecord第三部分:对象生命周期Active Record Part III:Object Life Cycle此前我们已经看到如何使用ActiveRecord来访问数据,以及如何连接多张表。

本章将会介绍ActiveRecord另一方面的重要内容:模型对象的生命周期。

我们将会看到如何定义校验逻辑和钩子方法。

20.1校验ValidationActiveRecord可以对模型对象进行校验。

校验可以在保存对象时自动进行,也可以通过编程的方式随时校验对象的当前状态。

如果在尝试保存模型对象时校验失败,这个对象就不会被写入到数据库;其中不合乎要求的状态会继续存在于内存中,这样你就可以——譬如说——将对象传回给输入表单,让用户有机会修改数据中的错误。

有些模型对象已经与数据库中的记录对应起来,有些还尚未建立这种对应。

对于这两种模型对象,ActiveRecord会区别对待。

如果一个对象刚刚创建出来,还没有与数据库记录建立映射,我们称之为新对象(new records),调用它的new_record?()方法会返回true。

当新对象的save()方法被调用时,ActiveRecord会执行一条insert语句将其存入数据库:而如果调用既有对象的save()方法,执行的SQL语句则是update语句。

两者的区别在ActiveRecord的校验流程上就会体现出来——你可以要求针对所有保存操作都执行校验,也可以要求只在创建或者更新时进行校验。

在调用validate()、validate_on_create()和validate_on_update类方法时列出一个或298第30章部署与生产多个方法名的符号,就可以指定你的校验逻辑。

validate()方法会在每次保存操作时都被调用,另外两个方法则分别是在保存新对象和保存既有对象时调用。

除了“将对象保存到数据库”之外,还可以在任意时候通过编程调用valid?()方法来校验模型对象的状态。

valid?()方法会调用validate()方法以及另一个校验方法(具体是哪一个取决于对象的状态),就跟调用save()方法时一样。

譬如说,下列代码会确保User对象的name属性始终有合法的值,并且新建User对象的name 值不与任何既有对象重复。

(稍后我们会看到如何更简单地指定这样的约束条件。

)class User<ActiveRecord::Basevalidate:valid_name?validate_on_create:unique_name?privatedef valid_name?unless name&&name=~/^\w+$/errors.add(:name,"is missing or invalid")endenddef unique_name?if User.find_by_name(name)errors.add(:name,"is already being used")endendend在上述代码中,如果校验方法遇到问题,就会调用errors.add()方法,在模型对象的错误列表中加上一条消息。

当调用此方法时,它传入的第一个参数是校验失败的属性,第二个参数则是出错信息。

如果你希望加入一条针对于整个模型对象的错误信息,则可以调用add_to_base)方法。

(请注意,下列代码使用了blank?()方法,如果被调用此方法的对象等于nil或者是空字符串,该方法就会返回true.)def one_of_name_or_email_requiredif name.blank?&&email.blank?errors.add_to_base("You must specify a name or an email address")endend在第493页我们将会看到,当Rails的视图要把表单显示给最终用户时,这个错误列表就会派上用场——有错误的字段会自动地高亮显示,你也可以很轻松地在表单顶上加上一个漂亮的错误列表框。

通过errors.on(:name)方法(或者它的别名errors[:name]),你也可以在程序中获取特定属性的错误信息。

调用errors.clear()方法则可以清空整个错误列表。

察看ActiveRecord::Errors 的API文档,你还可以找到别的一些方法,这些方法大多已经被一些高层的校验辅助方法覆盖了。

校验辅助方法Validation Helpers有些校验逻辑是很常见的:这个属性不能为空,那个属性的值必须在is到65之间,诸如此类。

ActiveRecord提供了一组标准的辅助方法,可以为模型对象加上这些校验逻辑。

这些辅助方法都是类方法,它们的名字都以validates_开头,它们的第一个参数都是一个属性名称的列表,并且后面可以跟上一个hash用以提供校验时的配置信息。

譬如说,前面提到的校验逻辑可以这样实现:class User<ActiveRecord::Basevalidates_format_of:name,1.1Rails是敏捷的299:with=>/^\w+$/,:message=>"is missing or invalid"validates_uniqueness_of:name,:on=>:create,:message=>"is already being used"end大部分validates_方法都接受:on和:message这两个选项。

:on选项用于指定校验进行的时机,可选的值有:save(默认值)、:create和:update。

:message选项用于指定出错信息。

如果校验失败,辅助方法会给模型对象加上一条出错信息,该信息将与校验失败的属性关联。

校验完毕之后,你可以通过模型对象的errors属性查看所有的错误列表。

当ActiveRecord作为Rails 应用的一部分使用时,“查看错误列表”的操作通常分为两个步骤进行:1.控制器尝试保存模型对象,但由于校验问题保存失败(返回false),于是控制器将包含无效数据的表单重新显示给用户。

2.视图模板使用error_messages_for()方法显示模型对象的错误列表,让用户有机会修改无效的输入值。

在第23.5节“错误处理与模型对象”(第493页)中,我们会详细介绍表单与模型对象之间的交互。

下面列出了模型对象中可以使用的校验辅助方法。

validates_acceptance_of检查单选框(checkbox)是否被选中。