#23
Apr 25
Counter Cache Column
If you need to display the record count for a has_many association, you can improve performance by caching that number in a column.
Update (3/29/08)
The migration code shown in this screencast does not work in Rails 2.0. Instead please use the code below. Special thanks to Josh Owens for this blog post describing the problem and solution.
# migrations/006_add_tasks_count.rb def self.up add_column :projects, :tasks_count, :integer, :default => 0 Project.reset_column_information Project.find(:all).each do |p| Project.update_counters p.id, :tasks_count => p.tasks.length end end def self.down remove_column :projects, :tasks_count end # models/task.rb belongs_to :project, :counter_cache => true
<!-- projects/index.rhtml --> <%= pluralize project.tasks.size, 'task' %>
You can also find the original code here which should work for Rails versions before 2.0.



very good
我永远顶你!!
Nice!
Доброго вам здоровья
Nice job. I really liked the migration part.
This is interesting. I probably never would have done this think it was redundant data. Thanks once again.
Another great screencast!
Ideas:
1) Setting up a Rails project using SVN (only a little off topic)
2) Deploying a Rails project using Capistrano
Keep it up Ryan!
Thank you! This screencast is very interesting and useful!
Great stuff -- I had no idea you could do that, and I learned some things about migrations too.
Thank you!
I would like to see acts_as_nested_set tutorial sometime. I'm currently doing an acts_as_nested_set with a self-referential, and it's not going too smooth. Love the screencasts - keep it up!
thanks!
будьте здоровы :)
I love the screencasts and the site! It has become first thing I check during my daily reading session. :)
I'm alse currently interested in act_as_nested_set - like ryan.
@David Parker: Railscasts’ sponsor, PeepCode, has a detailed screencast tutorial on Capistrano (with a free update to the version 2 screencast when that comes out):
http://www.peepcode.com/products/capistrano-concepts
Thanks Grant!... didn't check out that one yet. I ordered the RESTful one and I love it. I'll definitely look into it.
Thanks for the screencasts. They're great.
I am wondering why this approach is better than simply using length instead of size?
I never got this to work. I can see in the console, that the tasks_count has value when adding new tasks, but when finding all projects (with tasks) using project.tasks.size -method, I still see the "SELECT count(*) AS count_all FROM..." with as many ids as the projects. I have the counter_cache => true value in model. This is strange? (Is this only working in production -state?)
@jaffet, not sure what the problem is. It should work in development mode which is the mode I was in for this screencast. What version of Rails are you using?
Im using version 1.2.3
This is not working with the has_and_belongs_to_many relation.
If there are something like:
class Post < ActiveRecord::Base
has_and_belongs_to_many :tags, :counter_cache => true
end
will get an "ArgumentError" error:
Unknown key(s): counter_cache
how to resolve this situation?
@RainChen, I don't think Rails provides an easy way to do this with the has_and_belongs_to_many association. You may want to consider using has_many :through instead.
Alternatively you can try building your own custom counter cache by using the after_add and after_remove callbacks.
I trying the "after_add and after_remove" way.But I met a problem.
I can successfully update the counter cache when adding or destroying the associated record.But how about the updating?
Any tips,thx?
@taco: #length does an SQL query with AR, while #size uses the version in memory and therefore the cached number
Is it possible to maintain counters of complete and incomplete tasks?
Basically I need counters for each state in my child model, and this approach works for counting # of children right?
Thanks
@Andy, I think you'll need to keep track of this manually instead of using the counter_cache option. You'll have to set up an observer or callback to update the counter cache every time you change a task. You may want to ask this on railsforum.com where I can go into more detail.
Hi. Another great screencast! Thank you very much!
I'd like to do like a couple of other viewers and announce my interest in a cast about act_as_nested_set.
Thanks again...
I think it's not possible any more in rails edge (2.0) to fill the count-colums afterwards, because (from the edge api):
"Note: Specifying a counter_cache will add it to that model’s list of readonly attributes using attr_readonly."
Some other idea for this?
Beate,
I recently posted about this very issue on my blog. I ran into the same problem about a week ago.
Check it out:http://josh.the-owens.com/archives/2007/11/03/rails-edge-change-how-to-add-a-counter-cache-to-an-existing-db-table/
"Counter Cache migration article":http://josh.the-owens.com/archives/2007/11/03/rails-edge-change-how-to-add-a-counter-cache-to-an-existing-db-table/
Thanks Josh! It worked :)
Since knowledge of our ideas is a posteriori, the paralogisms of human reason, consequently, are by their very nature contradictory.
I would also like to see a railscast on acts_as_nested_set (maybe even combined with some drag and drop sorting!)
thank it helped me