Rails has_many through polymorphic counter cache

此生再无相见时 提交于 2019-12-03 20:22:50

Simply modify your Classification model for the following:

class Classification < ActiveRecord::Base
  attr_accessible :classifiable, :classifiable_id, :classifiable_type,
                  :taxonomy, :taxonomy_id, :taxonomy_type

  belongs_to :classifiable, :polymorphic => true
  belongs_to :taxonomy,     :polymorphic => true

  before_create  :increment_counter
  before_destroy :decrement_counter

  private

  # increments the right classifiable counter for the right taxonomy
  def increment_counter
    self.taxonomy_type.constantize.increment_counter("#{self.classifiable_type.downcase.pluralize}_count", self.taxonomy_id)
  end

  # decrements the right classifiable counter for the right taxonomy
  def decrement_counter
    self.taxonomy_type.constantize.decrement_counter("#{self.classifiable_type.downcase.pluralize}_count", self.taxonomy_id)
  end
end

Also, make sure you have the following columns in your taxonomies table:

t.integer :questions_count,           :null => false, :default => 0
t.integer :other_classifiables_count, :null => false, :default => 0
t.integer :other_classifiables_count, :null => false, :default => 0
t.integer :other_classifiables_count, :null => false, :default => 0

Change "other_classifiables_count" to what you need ("answers_count", "users_count", etc.)

It seems like Rails does not go through the before/after_destroy callbacks when calling delete (what happens when you remove a has many through association).

Instead, you can use the association's callbacks #before_add and #before_remove:

class Question < Classifiable
  has_many :categories, through: :classifications, 
                        as: :classifiable, 
                        source: :taxonomy, 
                        source_type: Category,
                        before_add: :increment_counter

  def increment_counter(category)
    # increment counter, etc.
  end

end

To modify Jonathan's answer a bit, you could make it look up the column type to see if it exists before incrementing/decrementing. I also DRYed it up a bit:

def increment_counter(direction=:increment)
  ar_class  = self.taxonomy_type.constantize
  ar_column = "#{self.taxonomy_type.underscore.pluralize}_count"

  if ar_class.columns.include? ar_column
    ar_class.send "#{direction}_counter", ar_column, self.taxonomy_id
  end
end

def decrement_counter
  increment_counter :decrement
end

Oh and it works with MultiWordClassNames. underscore does a downcase so my version omits it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!