对象的状态包括:initialize, create, update, destroy, load, validate, touch 当这些对象的状态改变的时候,会触发ActiveRecord的回调函数。
回调函数用法、指定action, 以及触发条件
#rails g model Article title
#回调函数的两种用法,直接使用回调块和指定回调函数名称
class Article < ApplicationRecord
validates :title, presence: { message: "can't be blank" }
#使用块函数
before_validation do
puts "use validate block "
end
#指定回调方法名称
before_validation :need_validate
private
def need_validate
puts "use validate method"
end
end
#指定回调的action
#before_validation回调函数会在create和update的时候出发,这里只是指定update, create的时候不触发
class Article < ApplicationRecord
validates :title, presence: { message: "can't be blank" }, on: :update
before_validation :need_validate
private
def need_validate
puts "use validate method"
end
end
#指定回调的条件
#下面面指定回调的条件,可以使用的条件包括if和unless
class Article < ApplicationRecord
validates :title, presence: { message: "can't be blank" }, if: :validate_condition?
before_validation :need_validate
private
def need_validate
puts "use validate method"
end
def validate_condition?
true
end
end
对象状态改变以及对应回调函数
#对象保存,create, create!, save, save!
before_validation
after_validation
before_save
around_save
after_save
before_create
around_create
after_create
after_commit/after_rollback
#对象更新,update(update_attributes), update!, update_attribute三个方法会触发
before_validation
after_validation
before_save
around_save
after_save
before_update
around_update
after_update
after_commit/after_rollback
#对象删除,destroy, destroy!, destroy_all三个方法会触发,delete, delete_all不会触发回调方法
before_destroy
around_destroy
after_destroy
after_commit/after_rollback
#load对象,all, first, find, find_by, last等方法会触发
after_find
after_initialize #load对象,首先执行after_find,然后再执行after_initialize
#initialize对象,new方法
after_initialize
#touch对象,touch方法触发
after_touch方法
#valid?
before_validation
#toggle! #guides中说该方法会触发回调,但未说明,下面只是说方法使用
Article.first.toggle!(:admin) #toggle!会改变值
Article.first.toggle(:admin) #toggle返回值会改变,但是本身值不变
transaction回调
#应用场景:数据库之外关联操作,比如删除照片,每一次的数据库操作都是一次transaction
after_commit #数据库提交之后
after_rollback #数据库rollback之后
#对比after_commit && after_save
操作在一个 transaction 中进行,即使 transaction 失败回滚,after_save 依然会触发,但 after_commit 不会
after_commit方法
#transaction有三种状态,分别是create, update, destroy, 对应如下三种commit
after_create_commit, after_update_commit, after_destroy_commit
#可以通过after_commit和动作结合的方式
after_commit :delete_disk_file, on: :destroy #=> after_destroy_commit :delete_disk_file
after_commit :delete_disk_file, on: :create #=> after_create_commit :delete_disk_file
after_commit :delete_disk_file, on: :update #=> after_update_commit :delete_disk_file
#示例,辅助代码参考controller part3
class Tag < ApplicationRecord
attr_accessor :attachment
after_destroy_commit :delete_disk_file
private
def delete_disk_file
path = "#{Rails.root}/public/uploads/#{self.id}"
if Dir.exist?(path)
unless Dir.empty?(path)
Dir.entries(path).select{|x| x =~ /[^.]/}.each do |file|
File.delete("#{path}/#{file}")
Dir.delete(path)
end
else
Dir.delete(path)
end
end
end
end
回调类
#/model/picture_file_callbacks.rb
#下面两个类都是在同一个文件夹中的不同类,PictureFile引入PictureFileCallbacks对象
#应用场景:复用
class PictureFileCallbacks
def after_destroy(picture_file)
puts "do something"
end
end
class PictureFile < ApplicationRecord
after_destroy PictureFileCallbacks.new
end
#PictureFile引入PictureFileCallbacks类
class PictureFileCallbacks
def self.after_destroy(picture_file)
puts "do something"
end
end
class PictureFile < ApplicationRecord
after_destroy PictureFileCallbacks
end