使用'counter_cache'时如何调用after_save回调?

时间:2011-05-07 00:46:25

标签: ruby-on-rails callback counter-cache after-save

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

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

class Author
  has_many :posts
end

我还为每个'author'使用了一个缓存片段,并且我想在@author.posts_count更新时使缓存过期,因为该值在UI中显示。问题是counter_cache(increment_counter和decrement_counter)的内部似乎没有调用Author上的回调,因此我无法知道它何时发生,除非从Post观察者中使缓存失效(或缓存清扫工具,这似乎并不干净。

有什么想法吗?

5 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分: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类中的一个使缓存片段到期的方法。

答案 2 :(得分: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

答案 3 :(得分:0)

enter image description here

我还要求观察计数器的变化。在挖掘rails源代码之后,通过直接SQL更新来更改counter_column。换句话说,它不会触发任何回调(在您的情况下,它不会在发布更新时触发作者模型中的任何回调)。

来自rails源代码的

,after_update回调也改变了counter_column。

我的方法是提高轨道,自己更新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

答案 4 :(得分:0)

我有类似的要求在计数器更新上执行某些操作,在我的情况下,如果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