当计数器缓存达到0时删除记录

时间:2013-04-11 16:57:27

标签: ruby-on-rails activerecord counter-cache

我有以下关系的模型:

+------+ 1    n +------------+ n    1 +-----+
| Post |--------| TagMapping |--------| Tag |
+------+        +------------+        +-----+

现在,在我的应用程序中,Post的{​​{1}}计数被非常频繁地读取,并且只有在添加新帖子时才会更改,与阅读相比,这种情况很少发生。因此,我决定将Tag属性添加到posts_count模型。

以下是我的ActiveRecord模型:

Post.rb:

Tag

TagMapping.rb:

class Post < ActiveRecord::Base

  # other stuff ... 

  # relations
  has_many :tag_mappings, dependent: :destroy
  has_many :tags, through: :tag_mappings

  # assign a new set of tags
  def tags=(new_tags)
    # generate a list of tag objects out of a listing
    if new_tags && !new_tags.instance_of?(Array)
      new_tags = new_tags.split(/\s+/).map do |tag|
        tag = Tag.find_or_initialize_by_name tag
        tag.save ? tag : false
      end.select {|v| v }
    end

    # remove the spare tags which aren't used by any posts
    ((tags || []) - new_tags).each do |tag|
      tag.destroy if tag.posts.count <= 1
    end

    # replace the old tags with the new ones
    tags.delete_all
    new_tags.each do |tag|
      # prevent tagging the post twice with the same tag
      tags << tag unless TagMapping.exists? post_id: self[:id], tag_id: tag.id
    end
  end
end

Tag.rb:

class TagMapping < ActiveRecord::Base

  # other stuff ...

  # create a cache for the post count in the Tag model
  belongs_to :tag, counter_cache: :posts_count
  belongs_to :post
end

当我销毁某个代码的所有帖子时,class Tag < ActiveRecord::Base # other stuff ... has_many :tag_mappings, dependent: :destroy has_many :posts, through: :tag_mappings end 会正确地缩减为0.但posts_count记录仍然存在。如果Tag达到0,我该如何删除记录?

1 个答案:

答案 0 :(得分:0)

我没有使用计数器缓存,只是使用after_destroyafter_create挂钩来跟踪帖子计数:

class TagMapping < ActiveRecord::Base

  # other stuff

  after_create :increment_post_count
  after_destroy :decrement_post_count

  def increment_post_count
    tag.posts_count += 1
    tag.save
  end

  def decrement_post_count
    tag.posts_count -= 1
    tag.save
    tag.destroy if tag.posts_count <= 0
  end
end