资料来源:Rails Guide
Guide
-回调和 ActiveRecord 生命周期
-认识回调方法以及如何使用它们
-在特殊的类中封装回调行为
1. Definition
Callback 是挂在 AR 对象生命周期上的一个个小钩子。当你的 Rails 程序中的每个对象被创建,更新,删除,甚至从数据库载入时都会惊动这一个个小钩子。你可以通过控制这些小钩子处理你想要处理的业务逻辑,但要提醒一下在钩子中的逻辑不宜太复杂,若确实有大量不可以免的操作,应该写一个单独的类用来处理这部分逻辑。
2. Types of Callbacks
2.1. Callbacks when create/update
-before_validation
-after_validation
-before_save
-around_save
-before_create/before_update
-around_create/around_update
-after_create/after_update
-after_save
-after_commit/after_rollback
2.2 Callbacks when destroy
-before_destroy
-around_destroy
-after_destroy
-after_commit/after_rollback
2.3 after_initialize
after_initialize
当模型对象被创建或是从数据库导入并初始化对象时调用。
Tips: 使用它可以避免你直接修改 AR 的initialize
方法。
2.4 after_find
after_find
当模型对象从数据库获取记录,并初始化为对象时调用。
Tips: after_find
在after_initialize
之前被调用。
2.5 after_touch
after_touch
该回调发生在一个模型对象记录被触摸时。
触摸表示更新 updated_at
字段,使用touch
方法可以手动完成记录的触摸。
3. Running and Skipping Callbacks
-(1) 产生回调:
create, update, update_attribute, update_attributes, destroy, destroy_all,
save, save(validate: false), valid?, increment!, decrement!, toggle!
after_find:
all, first, find, find_by, find_by_sql, last
-(2) 跳过回调:
touch, toggle, increment, decrement, increment_counter, decrement_counter,
update_counters, update_column, update_columns, update_all, delete, delete_all
4. Halting Execution
你所添加的回调函数会自动排成一个队列等待被执行,这个队列包括开头的验证,之后的回调,以及最后的数据库操作指令。该队列被包裹在一层事务中,如果任何一个回调函数出错 (throw(:abort)
或抛出异常,注意这里不包括返回false
),该链条的执行终止,并且向前回滚到最初的状态。
Tips: after_commit/after_rollback
发生在数据库操作之后,所以这里出错将会被无视
5. Conditional Callbacks
使用:if, :unless
来增加条件判断回调是否要执行.
6. Callback Classes
创建类来封装回调方法从而增加代码的可读性
7. Transaction Callbacks
after_commit
/after_rollback
是在数据库操作完成之后才被触发的。他们最佳的适用场景是在与别的外部系统交互时,操作无法成为数据库事务的一部分的时候。
如果你想完成删除数据库中的数据并且删除硬盘上的相关文件操作时,
最好使用 after_commit :delete_file_from_disk, on: :destroy
而不是 after_destroy :delete_file_from_disk
after_create_commit
等于 after_commit ... on: :create
after_update_commit
等于 after_commit ... on: :update
after_destroy_commit
等于 after_commit ... on: :destroy
相关零碎知识点:
- 可以在一个 callback 中定义多个方法,方法排列的次序就是方法执行的次序。
e.g. before_save :first, :second, :third # 执行顺序 :first, :second, :third
- 每当
create
/update
时,属性的改变都会存在attr_changed? == true
创建一条新的记录,在回调中attr_changed
=true,attr_was
=nil,attr
=当前值;
更新一条记录,在回调中attr_changed
=true,attr_was
=之前的值,attr
=当前值.
Note:attr_changed?
为true 是发生在你改变了这个记录的值却没有存入数据库的时候,另外创建记录时只要和默认值不一致都会返回 true。