免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 914 | 回复: 0
打印 上一主题 下一主题

确认:ActiveRecord::Callbacks [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-01-15 10:32 |只看该作者 |倒序浏览

可以把“回调”看成是对“确认”低级操作的廷续,在“模型”对象的生命周期内,“回调”给预了你更多的,更灵活的控制能力。
“回调”被钩挂在“活动记录”对象的生命周期中,它允许你在对象状态更改的前后触发逻辑。
做为“回调”的一个例子,让我们考虑Base#save调用:
(-) save 准备保存
(-) valid? 确认吗?
(1) before_validation 在确认前
(2) before_validation_on_create 创建新记录的确认前
(-) validate 确认
(-) validate_on_create 创建新记录确认
(3) after_validation 确认之后
(4) after_validation_on_create 创建新记录确认之后
(5) before_save 在保存之前
(6) before_create 在创建之前
(-) create 创建
(7) after_create 在创建之后
(8) after_save 在保存之后
这八个“回调”,可让你能够对“活动记录”生命周期内的每个状态做出强有力的处理。
一、可继承的回调队列

除了覆写回调方法之外,通过使用回调宏也可以注册回调。它的主要优点是宏增加了行为到回调队列中,而此回调队列保持了完整的继承层次。
也就是说子类在继承父类的同时也继承了回调,这样就构成了一个回调链。
二、回调类型

按回调宏划分一般认为有四种回调类型:方法引用(符号),回调对象,内联方法(使用过程对象--Proc),和内联eval方法(使用字符串)。
方法引用和回调对象方式是被推荐的,有时候使用带有Proc的内联方法是合适的(如用于创建混插),而内联eval方法是不赞成使用。
1、方法引用回调通过在对象内指定一个有效的protected或private方法来工作。像这样:
class Topic
before_destroy :delete_parents #方法引用
private
def delete_parents
self.class.delete_all "parent_id = #{id}"
end
end
2、“回调对象”是在回调名称之后唯一可带有参数的方法的名字。
class BankAccount
before_save EncryptionWrapper.new("credit_card_number") #带有参数的方法。
after_save EncryptionWrapper.new("credit_card_number")
after_initialize EncryptionWrapper.new("credit_card_number")
end
class EncryptionWrapper
def initialize(attribute)
@attribute = attribute
end
def before_save(record)
record.credit_card_number = encrypt(record.credit_card_number)
end
def after_save(record)
record.credit_card_number = decrypt(record.credit_card_number)
end
#注:此句是必须的。下面会提到。
alias_method :after_find, :after_save
private
def encrypt(value)
# Secrecy is committed
end
def decrypt(value)
# Secrecy is unveiled
end
end
之所以要使用“回调对象”,是因为我们要在“模型”间共享一些回调方法。只要简单地在app/models目录将要覆写的回调方法放在一个简单的类中,我们可以称它为“处理器类”,然后在要使用这个“处理器类”内回调方法的“模型”类中,创建该“处理器类”的一个实例,再将此实例放到回调名称之后即可。
在上面例子中,我们在 BankAccount 类中创建了新的 EncryptionWrapper 对象,并用这个对象钩住了before_save,after_save,after_initialize事件。所以你可以为一个回调名字指定你想传递的回调对象,当回调名字被触发时,对象内对应的被覆写的回调方法会被调用。
3、内联方法: 回调名字的后面不但可以是方法也可以是个块。
class Order
before_validation :normalize_credit_card_number
after_create do |order|
logger.info "Order #{order.id} created"
end
protected
def normalize_credit_card_number
self.cc_number.gsub!(/-w/, '')
end
end
4、通常“回调宏”通常接受一个符号,它们假设会运行的方法的符号,但是你也可以传递一个“方法字符串”,然后它将被计算
class Topic
before_destroy 'self.class.delete_all "parent_id = #{id}"'
end
注意,使用单引号是在回调被触发前不希望#{id}被计算。
四、特殊的 after_find 和 after_initialize

after_find和after_initialize,它没有相应的before_xxx回调。
after_find回调在任何find操作之后被调用,after_initialize在一个“活动记录模型”对象被创建之后被调用。
不像其它的回调,after_find和after_initialize只在有明确的定义时才会运行。而其它类型的回调,在这种情况下也会被调用。
Rails使用反射来确定是否调用回调。在完成实际的数据库操作时,完成这些操作的时间与在数据库上的相差不多。但是,数据库的单个select语句可以返回几百行,而要为每一行调用回调。这会明显地让处理慢下来。在这种情况下,Rails会分组完成。这是出于性能上的考虑。
出于性能优化的原因,对于after_find和after_initialize事件,只有一种方式定义“回调”,即把它们定义成方法。如果你试图使用第二种技术声明它们为处理器,它们将默默地被忽略。
五、取消回调

如果一个 before_* 回调返回 false ,则随后所有的回调和关联的方法将被取消。如果一个 after_* 回调返回 false ,则所有随后的回调被取消。回调通常按它们被定义的次序运行,带有异常的回调在“模型”


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/26076/showart_232037.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP