【问题标题】:Is there any method to disable after_find only in some cases是否有任何方法可以仅在某些情况下禁用 after_find
【发布时间】:2018-04-29 20:16:56
【问题描述】:

我在我的模型中使用 after_find,但在某些情况下想禁用。 我正在使用 .where after_find 仍在运行,但在文档中说它仅适用于以下方法。为什么会这样?

all
first
find
find_by
find_by_*
find_by_*!
find_by_sql
last

我的api(葡萄框架)是

delete '/delete_user' do
  user_id = params[:user_id] #authenticate_current_user!
  @user_profile = ::UserProfile.where(user_id: user_id).
  @user_profile.destroy_all
end

【问题讨论】:

  • 您从哪个文件中获得了这些信息? rails documentation 表示:“为每个由查找器找到并实例化的对象触发 after_findafter_initialize 回调”。自 v4 以来,find_by_* 方法已被弃用/移出核心轨道,并在轨道 5 中完全删除。
  • 您能出示您的代码吗? “在某些情况下禁用”是什么意思?您的问题可能有一个更干净的解决方案,根本不涉及after_find
  • 你能用自然语言描述你什么时候不想触发这个回调吗?
  • 看到“只要 Active Record 从数据库加载一个 RECORD,就会调用 after_find 回调。如果两者都定义了,则在 after_initialize 之前调用 after_find。”这也在文档中。我怀疑它是否适用于 where 子句,因为它在其中写了 A RECORD。

标签: ruby-on-rails ruby activerecord callback


【解决方案1】:

after_find 回调未被您的 where 调用调用;您的destroy_all 调用正在调用它。 destroy_all 将实例化每个 UserProfile 对象(及其关联对象)并逐个调用其 destroy 方法。

如果您想立即删除所有 UserProfile 对象,而不实例化它们(并跳过 all 回调),那么您可以调用:

UserProfile.where(user_id: user_id).delete_all

有关destroy_all and delete_all 之间差异的更多信息可以在 StackOverflow 上的其他答案中找到,但您关心的差异是:

  1. 它不会实例化记录
  2. 它不会删除关联的对象
  3. 它不会调用任何回调

我建议您不要像使用它那样使用after_find。有lots of ways to skip callbacks,但有almost nobody uses after_find。 (例如,与after_create 相比)

跳过after_find 回调的选项是有限的。没有built-in Rails methods 这样做。 (除了上面描述的)如果你绝对要保留回调,那么你最好的选择是在回调定义中添加一个条件:

after_find :foo, if: -> { <some logic> }

如果您使用这样的条件,那么您必须开始考虑如何在多线程环境中读取和设置该变量,以及如何在不创建竞争条件的情况下处理并发请求,这会让您走上一条丑陋的道路最好不要像您描述的那样使用after_find

【讨论】:

  • 没有。当我在控制台中尝试使用 where 子句时,会调用 after_find 。例如:User.where(id: 2) 调用 after_find 方法。
  • @shahanahamza 那只是因为您在控制台中运行它。如果您在控制台中运行UserProfile.where,那么irb 将实例化每条记录,以便方便地为您显示它们。当irb 实例化记录时,after_find 回调被触发。这会发生,因为控制台正在实例化记录以显示它们。
猜你喜欢
  • 2018-05-21
  • 1970-01-01
  • 2014-01-17
  • 1970-01-01
  • 2015-10-20
  • 2012-07-07
  • 2015-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多