Rails 3 2 counter cache not updating
Counting associations represents a performance improvement by avoiding eager loading and N 1 queries for listings -- e.g.the index page for Posts that shows how many Comments each Post has.
I have ended up going with a hybrid solution, where I use the counter cache only on pages where the count value cannot change (such as an index of articles with comment counts, explicitly using article.comments_count ). The link to Josh Owens' Website is not anymore working. The code in the migration *will* work, but before you set ":counter_cache = Here's the Evil Hack that temporarily makes your counter cache attribute non-readonly so that you can initialize it properly during up migration - Using the migration (as amended 03/29/08 - blog no longer available) on a large database took a very long time.On pages where the count can change, such as an article detail page with a new comment form and an ajaxy updated comments block, I use article.comments.length. Actually, using tasks.count in Rails 2.3 works so: Project.reset_column_information Project.find(:all)do |p| b.update_attribute :tasks_count, p.tasks.count end Is now fine and runs fast enough on a reasonable database size.But make sure this is run before setting counter_cache in the model.You may want to consider using has_many :through instead. I can successfully update the counter cache when adding or destroying the associated record. You'll have to set up an observer or callback to update the counter cache every time you change a task.Alternatively you can try building your own custom counter cache by using the after_add and after_remove callbacks. You may want to ask this on where I can go into more detail. | 0 (2 rows) id | post_id | body ---- --------- ----------- 2 | 1 | Comment 2 3 | 1 | Comment 3 (2 rows) SELECT * FROM posts; id | title | body | comments_count ---- ---------------- ----------------- ---------------- 1 | My first post!
| 1 (2 rows) CREATE TABLE posts ( id serial PRIMARY KEY, title text NOT NULL, body text NOT NULL, comments_count integer NOT NULL DEFAULT 0 ); CREATE TABLE comments ( id serial PRIMARY KEY, post_id integer NOT NULL REFERENCES posts(id), body text NOT NULL ); CREATE FUNCTION increment_counter(table_name text, column_name text, id integer, step integer) RETURNS VOID AS $$ DECLARE table_name text := quote_ident(table_name); column_name text := quote_ident(column_name); conditions text := ' WHERE id = $1'; updates text := column_name || '=' || column_name || ' ' || step; BEGIN EXECUTE 'UPDATE ' || table_name || ' SET ' || updates || conditions USING id; END; $$ LANGUAGE plpgsql; CREATE FUNCTION counter_cache() RETURNS trigger AS $$ DECLARE table_name text := quote_ident(TG_ARGV); counter_name text := quote_ident(TG_ARGV); fk_name text := quote_ident(TG_ARGV); fk_changed boolean := false; fk_value integer; record record; BEGIN IF TG_OP = 'UPDATE' THEN record := NEW; EXECUTE 'SELECT ($1).' || fk_name || ' !
For instance, what is the best way, or a very good way to go about handling a situation where you want to count only unread messages and also count the total number of messages with a counter_cache? but the unread have some conditions that would obviously need to be checked.
I've had nothing but problems implementing counter_cache in an ajaxy application.
I migrate tables where some inital row values in the db are generated using Model.create in the migration class, which cannot be done with counter caching.
Instead I just made a rake file with the same Model.create calls and that seems to work, if I just generate the values in a correct order. Ryan, do you have any experience or advice on working with counter_caches that also have conditions on them?
Counter cache works by performing an SQL update each time a new association is created or deleted.