使用“counter_cache”时如何调用 after_save 回调?

Posted

技术标签:

【中文标题】使用“counter_cache”时如何调用 after_save 回调?【英文标题】:How can I invoke the after_save callback when using 'counter_cache'? 【发布时间】:2011-05-07 00:46:25 【问题描述】:

我有一个为关联启用了 counter_cache 的模型:

class Post
  belongs_to :author, :counter_cache => true
end

class Author
  has_many :posts
end

我还为每个“作者”使用缓存片段,并且我希望在更新 @author.posts_count 时使该缓存过期,因为该值显示在 UI 中。问题是counter_cache(increment_counter 和 decrement_counter)的内部似乎没有调用 Author 上的回调,所以除了从 Post 观察者(或缓存)中使缓存过期之外,我无法知道它何时发生扫地机),它看起来并不那么干净。

有什么想法吗?

【问题讨论】:

【参考方案1】:

我有类似的要求在计数器更新时做某事,在我的情况下,如果 counter_cache 计数超过某个值,我需要做某事,我的解决方案是重写 update_counters 方法,如下所示:

class Post < ApplicationRecord
  belongs_to :author, :counter_cache => true
end

class Author < ApplicationRecord
  has_many :posts

  def self.update_counters(id, counters)
    author = Author.find(id)
    author.do_something! if author.posts_count + counters['posts_count'] >= some_value
    super(id, counters) # continue on with the normal update_counters flow.
  end
end

请参阅update_counters documentation 了解更多信息。

【讨论】:

【参考方案2】:

我也无法让它工作。最后我放弃了,写了自己的类似cache_counter的方法,从after_save回调中调用。

【讨论】:

感谢 Dex,我也会发布我想出的解决方案【参考方案3】:

我最终保持 cache_counter 不变,但随后通过 Post 的 after_create 回调强制缓存过期,如下所示:

class Post
  belongs_to :author, :counter_cache => true
  after_create :force_author_cache_expiry

  def force_author_cache_expiry
    author.force_cache_expiry!
  end
end

class Author
  has_many :posts

  def force_cache_expiry!
    notify :force_expire_cache
  end
end

那么 force_expire_cache(author) 是我的 AuthorSweeper 类中的一个方法,它使缓存片段过期。

【讨论】:

【参考方案4】:

好吧,我也遇到了同样的问题,最后出现在你的帖子中,但我发现,由于“after_”和“before_”回调是公共方法,你可以执行以下操作:

class Author < ActiveRecord::Base
  has_many :posts

  Post.after_create do
    # Do whatever you want, but...
    self.class == Post # Beware of this
  end
end

我不知道这样做有多少标准,但是方法是公开的,所以我想是可以的。

如果你想保持缓存和模型分开,你可以使用Sweepers。

【讨论】:

【参考方案5】:

我也有观察柜台变化的需求。挖掘 Rails 源代码后,通过直接 SQL 更新更改 counter_column。换句话说,它不会触发任何回调(在您的情况下,它不会在 Post 更新时触发 Author 模型中的任何回调)。

从 rails 源代码,counter_column 也被 after_update 回调改变了。

我的做法是让rails向上,自己更新counter_column:

class Post
  belongs_to :author
  after_update :update_author_posts_counter

  def update_author_posts_counter
    # need to update for both previous author and new author

    # find_by will not raise exception if there isn't any record
    author_was = Author.find_by(id: author_id_was) 

    if author_was
      author_was.update_posts_count!
    end
    if author
      author.update_posts_count!
    end
  end
end

class Author
  has_many :posts
  after_update :expires_cache, if: :posts_count_changed? 

  def expires_cache
    # do whatever you want
  end

  def update_posts_count!
    update(posts_count: posts.count)
  end
end

【讨论】:

以上是关于使用“counter_cache”时如何调用 after_save 回调?的主要内容,如果未能解决你的问题,请参考以下文章

带条件的 counter_cache

如何在androidmainfest.xml中调用自动对焦功能

使用ctypes和python并调用libc accept时的EFAULT

C#泛型参数的数据结构还原?

如何使用Alamofire Router来组织API调用?(swift Alamofire5)

当我键入 AF.request 时,啥都没有显示,但 Alamofire.request 正在工作,但 .GET 功能仍然没有显示。我如何解码数据