当使用“counter_cache”时,我该如何调用“after_save”回调函数?

3

我有一个模型,它启用了关联的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观察器(或缓存清除程序)中使缓存失效之外,我无法知道何时发生这种情况,但这种方法看起来并不太好。 有任何想法吗?
5个回答

2

我有一个类似的需求,需要在计数器更新时做一些事情。在我的情况下,如果计数器缓存的数量超过了某个值,我需要执行一些操作。我的解决方案是重写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文档获取更多信息。


0

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


谢谢Dex,我也会发布我想出的解决方案。 - Carter

0

嗯,我遇到了同样的问题,最终看到了你的帖子,但我发现,由于“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


0
我最终保留了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类中用于过期缓存片段的方法。


0

enter image description here

我还有一个要求,需要观察计数器的变化。在查看Rails源代码后,发现counter_column是通过直接SQL更新更改的。换句话说,在您的情况下,当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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接