对象的状态包括: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

results matching ""

    No results matching ""