在rails中实现自定义callback功能

405 阅读4分钟

什么是回调

回调的概念和作用

回调是一种编程机制,允许我们在特定事件发生时执行预定义的代码块或方法。当某个事件触发时,系统会调用已注册的回调函数,以执行相关的操作或逻辑。回调在软件开发中被广泛应用,可以用于处理异步操作、事件处理、状态变化等情况。

回调的种类和触发时机

  1. 前置回调(before callbacks): 在目标事件之前执行的回调,常见的前置回调包括 before_savebefore_create 等。它们在执行目标操作之前执行,通常用于进行数据验证、预处理或设置默认值等操作。
  2. 后置回调(after callbacks): 在目标事件之后执行的回调,常见的后置回调包括 after_saveafter_create 等。它们在执行目标操作之后执行,通常用于发送通知、记录日志、执行其他业务逻辑等操作。
  3. 环绕回调(around callbacks): 包围目标事件的回调,常见的环绕回调包括 around_savearound_create 等。它们允许在目标操作之前和之后执行自定义的代码,可以对目标操作进行更细粒度的控制和修改。

回调的触发时机与模型的生命周期相关,例如创建记录、更新记录、保存记录等。不同的回调种类和时机提供了灵活的方式来处理模型的状态变化和相关操作。

Rails内置回调方法

常见的内置回调方法:

  1. before_ 回调方法:

    • before_validation:在验证之前执行的回调。
    • before_save:在保存之前执行的回调。
    • before_create:在创建记录之前执行的回调。
    • before_update:在更新记录之前执行的回调。
    • before_destroy:在删除记录之前执行的回调。
  2. after_ 回调方法:

    • after_validation:在验证之后执行的回调。
    • after_save:在保存之后执行的回调。
    • after_create:在创建记录之后执行的回调。
    • after_update:在更新记录之后执行的回调。
    • after_destroy:在删除记录之后执行的回调。
  3. around_ 回调方法:

    • around_save:在保存之前和之后执行的回调。
    • around_create:在创建记录之前和之后执行的回调。
    • around_update:在更新记录之前和之后执行的回调。
    • around_destroy:在删除记录之前和之后执行的回调。

源码中是如何定义这些方法的

在rails中所有的model模型都是继承于 ApplicationRecord 类,ApplicationRecord 类又继承于 ActiveRecord::Base类,所以我们在rails中使用的回调方法都是来自于 ActiveRecord::Base类。

rails6.0版本为例,ActiveRecord::Base部分源码 截屏2023-06-25 16.34.16.png 其中关键的三个module

  1. include DefineCallbacks(rails 7 中这个移除了,代码迁移到Callbacks)

截屏2023-06-25 16.48.28.png 主要作用定义回调方法定义模型回调方法 :initialize, :find, :touch 的回调钩子,只在 :after 时机触发。 定义模型回调方法 :save, :create, :update, :destroy 的回调钩子,在默认时机触发。

这里的方法define_model_callbacks来自于ActiveModel::Callbacks模块,而ActiveModel::Callbacks 又依赖于ActiveSupport::Callbacks模块,这个模块才是实现回调方法的核心。

截屏2023-06-26 16.40.44.png

截屏2023-06-26 16.40.56.png

  1. include Callbacks
  2. include Transactions 用于管理数据库事务。它提供了一种机制,确保数据库操作的原子性和一致性,在里面定义了一些回调与 commit、rollback 相关
ACTIONS = [:create, :destroy, :update]

included do
  define_callbacks :commit, :rollback,
                   :before_commit,
                   :before_commit_without_transaction_enrollment,
                   :commit_without_transaction_enrollment,
                   :rollback_without_transaction_enrollment,
                   scope: [:kind, :name]
end

rails自定义回调方法

当使用 define_callbacks 方法自定义回调时,可以按照以下步骤进行操作:

  1. 在需要定义回调的类(通常是模型类)中引入 ActiveSupport::Callbacks 模块:

    include ActiveSupport::Callbacks
    
  2. 使用 define_callbacks 方法定义回调:

    define_callbacks :my_callback
    
  3. 在需要触发回调的地方调用 run_callbacks 方法:

    run_callbacks :my_callback do
      # 执行回调的相关操作
    end
    
  4. 定义具体的回调方法:

    set_callback :my_callback, :before do |object|
      # 在回调之前执行的逻辑
    end
    
    set_callback :my_callback, :after do |object|
      # 在回调之后执行的逻辑
    end
    

通过以上步骤,可以自定义回调并将其与特定事件相关联。可以在回调方法的前后执行需要的逻辑操作。回调方法可以在 beforeafteraround 时机执行,具体根据需求进行设置。

class Article < ApplicationRecord
  validates :title, presence: true, length: { minimum: 6, maximum: 100}
  validates :description, presence: true, length: { minimum: 10, maximum: 300}
  
  define_callbacks :my_callback
  def my_callback
    run_callbacks :my_callback do
      puts "my_callback"
    end
  end

  set_callback :my_callback, :before do |obj|
    puts  "before#{obj.inspect}"
  end
  set_callback :my_callback, :after, :after_my_callback

  def after_my_callback
    puts "after#{self.inspect}"
  end
end