Rails中使用after_commit区分create/update/delete操作实现用户同步
解决方案
Rails ActiveRecord 已经内置了完整的特性支持你的需求,有两种常用实现方式:
方案1:按操作拆分独立回调(推荐)
利用 after_commit 支持的 on 参数直接绑定对应操作,逻辑拆分清晰,维护成本更低。
代码示例:
class User < ApplicationRecord # 绑定创建操作的回调 after_commit :sync_create_third_party, on: :create # 绑定更新操作的回调 after_commit :sync_update_third_party, on: :update # 绑定删除操作的回调 after_commit :sync_destroy_third_party, on: :destroy private def sync_create_third_party # 仅active状态的新用户需要同步创建 return unless is_active? # 调用第三方创建用户逻辑,建议丢异步任务执行 ThirdPartyUserService.create(id, email, username) end def sync_update_third_party # 仅is_active字段变更时需要处理 return unless saved_change_to_is_active? # 取变更前后的值,格式为 [旧值, 新值] old_active_state, new_active_state = saved_change_to_is_active if new_active_state ThirdPartyUserService.create(id, email, username) else ThirdPartyUserService.destroy(id) end end def sync_destroy_third_party ThirdPartyUserService.destroy(id) end end
方案2:单个回调内判断操作类型
如果需要把所有同步逻辑收敛到同一个方法内,可以用ActiveRecord内置的transaction_include_any_action?方法判断当前事务的操作类型。
代码示例:
class User < ApplicationRecord after_commit :sync_third_party_user private def sync_third_party_user # 先判断删除操作 if transaction_include_any_action?([:destroy]) ThirdPartyUserService.destroy(id) return end # 判断创建操作 if transaction_include_any_action?([:create]) return unless is_active? ThirdPartyUserService.create(id, email, username) # 判断更新操作 elsif transaction_include_any_action?([:update]) return unless saved_change_to_is_active? old_state, new_state = saved_change_to_is_active new_state ? ThirdPartyUserService.create(id, email, username) : ThirdPartyUserService.destroy(id) end end end
注意事项
- 第三方接口调用建议放到异步任务中执行,避免第三方接口超时、报错影响主业务流程,同时避免事务未提交就调用接口导致的数据不一致
- 如果你使用的Rails版本低于5.1,没有
saved_change_to_*方法,可以替换为previous_changes[:is_active]获取字段变更前后的值 - 建议增加同步失败的重试、告警机制,避免第三方服务波动导致两边数据不一致
内容的提问来源于stack exchange,提问作者opensource-developer
相关产品推荐
相关产品推荐

