Rails:在 after_commit 中调用相同的方法来创建、更新、删除,但根据某些标志做不同的事情

Posted

技术标签:

【中文标题】Rails:在 after_commit 中调用相同的方法来创建、更新、删除,但根据某些标志做不同的事情【英文标题】:Rails: call same method in after_commit for create, update, delete but do separate things based on certain flags 【发布时间】:2022-01-12 12:41:00 【问题描述】:

我想根据以下场景在 3rd 方服务上创建和删除用户

    在第 3 方创建用户

    在应用程序中创建用户时 从inactive 标记为active(我的用户模型上有一个名为is_active 的列)

    删除第三方用户

    当用户从应用程序中删除时 标记为inactive

看起来我可以使用after_commit 回调,但我如何在after_commit 中识别该操作是createupdatedelete

对此的任何帮助都会有所帮助。

【问题讨论】:

您可以使用:on 选项指定回调只应由特定操作触发:after_commit :do_foo, on: :createafter_commit :do_bar, on: :updateafter_commit :do_foo_bar, on: [:create, :update] 【参考方案1】:

不要为此使用回调——你会后悔的。 回调的主要问题是:

没有上下文 - 您实际上不知道应用程序中发生了什么。 很难控制回调实际触发的时间 - 更重要的是,当您不希望它触发时(例如在加载固定装置时)。 这让模型承担了太多责任。 您无法独立于创建/更新/销毁记录来测试回调逻辑。

当您似乎也在处理第三方 API 时,我真的不能低估这一点。当您触及应用程序边界时使用隐式机制(如回调)是一个非常糟糕的主意。通过单一方法管道传输所有内容的整个想法也不合理。

相反,您可以使用service objects 等模式来处理模型的“转换”。

class UserCreationService
  def initialize(user)
    @user = user
  end

  def perform
    # do something with @user
  end
end


class UserInactivationService
  def initialize(user)
    @user = user
  end

  def perform
    # do something with @user
  end
end

它们只做一项工作并且易于测试,并且只有在您明确希望它们时才会触发。 ActiveJob 实际上就是这种模式的一个例子。

【讨论】:

感谢@max 的回复。所以我需要显式调用服务,例如,当创建用户时,在RegistrationController 我需要调用在第 3 方创建用户的服务 是的,这就是重点。

以上是关于Rails:在 after_commit 中调用相同的方法来创建、更新、删除,但根据某些标志做不同的事情的主要内容,如果未能解决你的问题,请参考以下文章

Rails 从视图中调用操作

如何在 Rails 中使用 Cloudinary 将直接上传字段与模型相关联?

Rails - 如何让两个用户 ID 与模型相关联

Rails 和 SQL - 与数组、条目中的所有元素相关联

与Ruby on Rails中的范围相关联

将用户与 Rails 中的嵌套模型相关联