回调可以再对象的状态改变之前或之后触发指定的逻辑操作。
回调是在对象生命周期的特定时刻执行的方法。回调方法可以在Active Record对象创建,保存,更新,删除,验证或是从数据库中读出时执行。
在使用回调之前,需要先注册。回调方法的定义和普通的方法一样,然后使用类方法注册。
class User < ActiveRecord::Base validates :login, :email, presence: true before_validation :ensure_login_has_a_value protected def ensure_login_has_a_value if login.nil? self.login = email unless email.blank? end end end
这种类方法还可以接受一个代码块。如果操作可以使用一行代码表述,可以考虑使用代码块形式:
class User < ActiveRecord::Base validates :login, :email, presence: true before_create do self.name = login.capitalize if name.blank? end end
注册回调时可以指定只在对象生命周期的特定事件发生时执行:
class User < ActiveRecord::Base before_validation :normalize_name, on: :create after_validation: set_location, on: [:create, :update] protected def normalize_name self.name = self.name.downcase.titleize end def set_location self.location = LocationService.query(self) end end
一般情况下,都会把回调方法定义为受保护的或是私有方法。
创建对象
before_validation | after_validation |
before_save | after_save |
around_save | around_create |
before_create | after_create |
before_validation | after_validation |
before_save | after_save |
around_save | around_update |
before_update | after_update |
before_destroy | around_destroy |
after_destroy | |
after_initialize和after_find
after_initialize回调在Active Record对象初始化时执行,包括使用new和从数据库中读取记录。
after_find回调在数据库中读取记录时执行。如果同时注册了after_find和after_initialize回调,after_find会先执行。
after_touch
after_touch回调在碰触Active Record对象时执行。
执行回调 方法触发执行回调
跳过回调
终止执行
在模型中注册回调后,回调会加入一个执行队列。这个队列中包含模型的数据验证,注册的回调,以及要执行的数据库操作。
整个回调链包含在一个事务中。如果任意一个before_*回调方法返回false或是抛出异常,整个回调链都会终止执行,撤销事务;
而after_*回调只有抛出异常才能达到相同的效果。
关联回调
回调能在模型关联中使用,甚至可有关联定义。
条件回调
条件通过:if和:unless选项指定,选项的值可以是Symbol、字符串、Proc或数组。
if选项指定什么时候调用回调,unless指定什么时候不调用回调。
使用Symbol时,表示要在调用回调之前执行对应的判断方法。
使用字符串时,但必须是Ruby代码,传入eval方法中执行,
使用Proc,这种形式最适合用在同一行代码能表示的条件上
有时回调方法可以在其他模型中重用,可以将其封装到类中。
还有两个回调会在数据库事务完成时触发:after_commit和after_rollback。