Marcio Trindade

Counter cache com acts_as_tree

Estava fazendo uns testes esses dias com uma aplicação Rails que utiliza acts_as_tree. Estava utilizando o methodo size para saber se o objeto tinha filhos, foi então que me veio a idéia de implementar um counter_cache e assim dar uma boa limpada nas consultas executadas.

Pesquisei na documentação como fazer isso e bastava colocar o campo com o nome de children_count, porém quando adicionei o :counter_cache => true no act_as_tree o autotest já me acusou 2 erros de SQL. Com uma pesquisada no Google consegui encontrar a solução, basta usar o nome do campo como parâmetro para o counter_cache.

Criando a migration

console
script/generate migration add_pages_count

Então editei ela para ficar com o código abaixo, atente para o nome children_count do campo.

add_pages_count.rb
class AddPagesCount < ActiveRecord::Migration
  def self.up
    add_column :pages, :children_count, :integer, :default => 0
    Page.reset_column_information
    Page.all.each do |p|
      Page.update_counters p.id, :children_count => p.children.count
    end
  end
  def self.down
    remove_column :pages, :children_count
  end
end

execute a migration tanto no seu banco de desenvolvimento como no test.

console
rake db:migrate && rake db:migrate RAILS_ENV=test

Adicionando o counter_cache

A solução está exatamente aqui, descobri que basta você passar o nome do campo que deseja usar para o counter_cache, ficou assim:

page.rb
class Page < ActiveRecord::Base
  acts_as_tree :counter_cache => "children_count"
end

Tests

Agora uma alteração que eu tive que fazer nos meus teste foi adicionar o filho com o metodo create e não como o new

page_test.rb
require File.dirname(__FILE__) + '/../test_helper'
class PageTest < Test::Unit::TestCase
  context "A page instance" do
    should "be able to have children" do
      assert_difference "Page.count", 1 do
        assert_difference "pages(:home).children.size", 1 do
          pages(:home).children.create(:title=>"Sign Up", :body=>"Sign up text!")
        end
      end
    end
  end
end

Bom é só isso simples assim, espero que possa ajudar alguém.