为数据模型自定义回调
Overview
在本指南中,您可以学习;了解如何在 Mongoid 模型中实现回调,以自定义模型实例的生命周期。
回调是 Mongoid 在对象生命周期的指定时刻触发的方法。 它们允许您在对象状态更改之前或之后启动指定的操作。
Mongoid 实现了来自 Active Record 的许多回调。 要学习;了解详情,请参阅 Active Record 文档中的 回调 。
支持的回调
after_initialize
after_build
before_validation
after_validation
before_create
around_create
after_create
after_find
before_update
around_update
after_update
before_upsert
around_upsert
after_upsert
before_save
around_save
after_save
before_destroy
around_destroy
after_destroy
要学习;了解有关上述任何回调类型的更多信息,请参阅 Rails API文档中的 ActiveRecord::Callbacks 参考。
您可以在顶层和嵌入式文档模型中实现回调。
注意
回调调用行为
为了效率,Mongoid 仅对您执行持久性动作的文档回调回调。 这种行为使 Mongoid 能够支持大型层次结构,并通过不在整个文档层次结构中调用回调来有效地处理优化的原子更新。
在实现领域逻辑的回调时,请采取预防措施并确保可测试性,因为当链中的回调停止执行时,这些设计可能会导致意外错误。 我们建议对程序核心功能之外的横切关注点使用回调,例如对背景作业进行排队。
文档回调
您必须在模型类上实现和注册回调。 您可以使用普通方法、区块和 Proc
对象来注册回调,也可以定义使用类或模块的自定义回调对象。
此示例演示了如何通过以下方式在 Contact
模型类上注册回调:
包括
before_save
类方法,该方法会在将Contact
实例保存到MongoDB之前触发process_phone
方法。process_phone
方法在类中单独定义。包括
after_destroy
类方法,并在删除Contact
实例时使用区块打印消息。
class Contact include Mongoid::Document field :name, type: String field :phone, type: String # Creates a callback to clean phone numbers before saving before_save :process_phone protected def process_phone self.phone = phone.gsub(/[^0-9]/, "") if attribute_present?("phone") end # Creates a callback to send a message about object deletion after_destroy do p "deleted the contact for #{name}" end end
以下代码执行演示回调操作的数据操作:
Contact.create(name: 'Serena Atherton', phone: '999 555-3030') # => `phone` field saved as '9995553030' Contact.create(name: 'Zayba Haq', phone: '999 123?5050') # => `phone` field saved as '9991235050' Contact.first.destroy # => Console message: "deleted the contact for Serena Atherton"
由于回调功能来自 Active Support,因此您也可以使用 set_callback
类方法语法来注册回调。 以下代码演示了如何使用此语法创建回调,将 name
字段的原始值存储在 aliases
大量中:
class Contact include Mongoid::Document field :name, type: String field :phone, type: String field :aliases, type: Array, default: [] set_callback(:update, :before) do |document| if document.name_changed? document.push(aliases: document.name_was) end end end Contact.create(name: 'Xavier Bloom', phone: '4447779999') Contact.first.update(name: 'Xav - coworker') # Saved document in MongoDB: # {"aliases":["Xavier Bloom"],"name":"Xav - coworker","phone":"4447779999"}
关联回调
Mongoid 提供以下关联回调:
after_add
after_remove
before_add
before_remove
如果您在模型类上注册关联回调,则每当您从以下任何关联中添加或删除文档时都会调用该关联回调:
embeds_many
has_many
has_and_belongs_to_many
将关联回调指定为相应关联的选项。 您必须将添加或删除的文档作为参数传递给指定的回调。
以下代码演示了如何在嵌入多个 SavedArticle
实例的 User
模型类上注册关联回调,以限制单个实例嵌入文档的数量:
class User include Mongoid::Document field :username, type: String # Registers the callback in the association statement embeds_many :saved_articles, before_add: :send_message protected # Passes the association document as a parameter to the callback def send_message(saved_article) if saved_articles.count >= 10 p "you can't save more than 10 articles at a time" throw(:abort) end end end class SavedArticle include Mongoid::Document embedded_in :user field :url, type: String end
更多信息
要学习;了解如何阻止 Mongoid运行回调,请参阅 Active Record 文档中的以下参考资料: