9.1 注册回调 使用回调有个规则就是要注册它们。就像平常使用方法一样,使用一个macro-style类方法来注册。 class User < ActiveRecord::Base validates_presence_of :login, :email before_validation :ensure_login_has_a_value
protected def ensure_login_has_a_value if login.nil? self.login = email unless email.black? end end end macro-style类方法也接受一个block,如果代码很短就可以考虑把它写在block中。 class User < ActiveRecord::Base validates_presence_of :login, :email before_create { |user| user.name = user.login.capitalize if user. name.blank ?} end
当从数据库中载入记录时就可以使用after_find,如果两种方法都定义了,after_find是在after_initialize之前调用。 这两个回调方法和其它的有一点点不同,它们没有before_*的版本。而且注册他们唯一的方法就是定义方法。如果使用macro-style来注册的话,会被忽略掉。 class User < ActiveRecord::Base def after_initialize puts "You have initialized an object!" end def after_find puts "You have found an object!" end end
>> User.new You have initialize an object! => #<User id: nil>
>>User.first You have found an object! You have initialized an object! =>#<User id: 1>
15.1 使用符号的:if和:unless 使用的符号参数一般是指向一个方法,如果这个方法返回false,那么回调就不执行。 class Order < ActiveRecord::Base before_save :normalize_card_number, :if => :paid_with_card? end
15.2 使用字符串的:if和:unless 字符串参数是可能通过eval执行的Ruby代码。当描述一个很短的条件时可以用它。 class Order < ActiveRecord::Base before_save :normalize_card_number, :if => "paid_with_card?" end
15.3 使用Proc对象的:if和:unless 通过条件在一行时,使用这个参数是再好不过的了。 class Order < ActiveRecord::Base before_save :normalize_card_number, :if => Prod.new{|order| order.paid_with_card?} end
15.4 多条件的回调 当用条件来限制回调时,可以把:if和:unless同时写上。 class Comment < ActiveRecord::Base after_create :send_email_to_author, :if => :author_wants_emails?, :unless => Proc.new{ |comment| comment.post.ingnore_comment?} end
16 回调类 虽然多数情况下,使用内建的回调方就足够了。ActiveRecord也让你可以自己定义类来创建回调方法,而且这个过程很容易。 class PictureFileCallbacks def after_destroy(picture_file) File.delete(picture_file.filepath) if File.exists?(picture_file.filepath) end end
当在类中声明一个回调方法,会用模型对象作为参数。可以这样来使用: class PictureFile < ActiveRecord::Base after_destroy PictureFileCallbacks.new end 我们声了一个回调的实例方法,这样就要实例化一个PictureFileCallbacks对象。很多时候会用类方法: class PictureFileCallbacks def self.after_destroy(picture_file) File.delete(picture_file.filepath) if File.exists?(picture_file.filepath) end end
如果回调方法是这样定义的,就不用实例化了。 class PictureFile < ActiveRecord::Base after_destroy PictureFileCallbacks end
17.1 创建观察者 例如,User模型要为每个新创建的用户发送email。因为发送email和我们的模型没有直接的联系,所以就创建观察者来包含这些功能。 class UserObserver < ActiveRecord::Observer def after_create(model) # code to send confirmation email... end end
17.3 共享观察者 观察者可以添加到更多的模型中: class MailerObserver < ActiveRecord::Observer observe :registration, :user def after_create(model) # code to send cofirmation email... end end