Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

counter_cache in single table inheritance

I am wondering if the counter_cache would work in single table inheritance.

For these models:

class User
  has_many :questions
end

class Question
  belongs_to :user, :counter_cache => true
end

class SimpleQuestion < Question
end
class ComplexQuestion < Question
end

So will the following counters work?

create_table(:users) do |t|
  t.integer :questions_count
  t.integer :simple_questions_count
  t.integer :complex_questions_count
end
  1. All of them work
  2. None of them work
  3. Only questions_count work
  4. Only simple_questions_count and complex_questions_count

Which one? I am guessing the 3rd, but I want 4 more. If it's not 4, how do I make 4 work?

=== UPDATE ===

Here is an example:

id, user_id, question_content, type
1, 3, something, SimpleQuestion
2, 3, something, SimpleQuestion
3, 3, something, ComplexQuestion

So now I want:

user.questions_count # => 3
user.simple_questions_count # => 2
user.complex_questions_count # => 1

My question is, what's the basic behavior of :counter_cache => true and is it possible to apply on single table inheritance?

like image 641
PeterWong Avatar asked Oct 20 '10 16:10

PeterWong


People also ask

How does the single-table inheritance work?

In Single-Table Inheritance (STI), many subclasses inherit from one superclass with all the data in the same table in the database. The superclass has a “type” column to determine which subclass an object belongs to. In a polymorphic association, one model “belongs to” several other models using a single association.

What is Counter_cache?

Counter Cache Definition For any parent model with an associated child model, the counter_cache is an integer database column with the value maintained by the Rails framework. An application should treat it as read-only. The column contains a pre-calculated number of associated children.

What is single-table inheritance in Rails?

Single-table inheritance (STI) is the practice of storing multiple types of values in the same table, where each record includes a field indicating its type, and the table includes a column for every field of all the types it stores.


2 Answers

Just faced the same situation and it worked for me as you expected (num 4):

Look, modify your code like this, so that sub-classes would override parents behavior:

class User
  has_many :questions
end

class Question
  belongs_to :user
end

class SimpleQuestion < Question
  belongs_to :user, :counter_cache => true
end
class ComplexQuestion < Question
  belongs_to :user, :counter_cache => true
end

And add complex_questions_count and simple_questions_count columns to your User

Thats it! whenever you create a are question it would increment the proper counter. Tested it on rails 3.2!

like image 173
prikha Avatar answered Sep 29 '22 15:09

prikha


Looking through the source code where ":counter_cache" is implemented, it does not look like it supports the sort of counting you need. Fortunately, it is easy to roll your own here. Just update Question to track the counts manually, like so:

class Question
  belongs_to :user

  after_create :increment_counts
  before_destroy :decrement_counts

  protected

  def increment_counts
    User.increment_counter :questions_count, user_id
    User.increment_counter "#{type.pluralize.underscore}_count", user_id
  end

  def decrement_counts
    User.decrement_counter :questions_count, user_id
    User.decrement_counter "#{type.pluralize.underscore}_count", user_id
  end
end
like image 22
Ben Lee Avatar answered Sep 29 '22 16:09

Ben Lee