In Rails, to automatically count associations, you do:
class Script
has_many :chapters
end
class Chapter
belongs_to :script
end
and you add a chapters_count column into the Script model.
Now, what if you want to count the number of paragraphs in a Script without having a script_id key in the paragraph model ?
class Script
has_many :chapters
has_many :paragraphs # not complete
end
class Chapter
has_many :paragraphs
belongs_to :script
end
class Paragraph
belongs_to :chapter
end
How do you automatically associate script to paragraph and count them using the automatic count of Rails ?
You're on the right track. But first you've got to address a small error. Rails won't update a counter cache unless you instruct it to.
class Chapter
belongs_to :script, :counter_cache => true
end
Will automatically update @script.chapter_count before creation and after destruction of all associated Chapters.
Unfortunately things aren't so simply when dealing :through relationships. You will need to update the associated script's paragraph counter through callbacks in the Paragraph model.
N.B.: The following assumes you want to keep a paragraph counter in Chapter as well.
Start by applying the same theory to the Chapter model, and a paragraphs count column to the Script table.
class PrepareForCounterCache < ActiveRecord::Migration
def self.up
add_column :scripts, :paragraphs_count, :integer, :default => 0
add_column :chapters, :paragraphs_count, :integer, :default => 0
Chapter.reset_column_information
Script.reset_column_information
Chapter.find(:all).each do |c|
paragraphs_count = c.paragraphs.length
Chapter.update_counters c.id, :paragraphs_count => paragraphs_count
Script.update_counters c.script_id, :paragraphs_count => paragraphs_count
end
end
def self.down
remove_column :scripts, :paragraphs_count
remove_column :chapters, :paragraphs_count
end
end
Now to set up the relationships:
class Script
has_many: chapters
has_many: paragraphs, :through => :chapters
end
class Chapter
has_many: paragraphs
belongs_to :script, :counter_cache => true
end
class Paragraph
belongs_to :chapter, :counter_cache => true
end
All that's left is to tell Paragraph to update the paragraph counters in script as a callback.
class Paragraph < ActiveRecord::Base
belongs_to :chapter, :counter_cache => true
before_save :increment_script_paragraph_count
after_destroy, :decrement_script_paragraph_count
protected
def increment_script_paragraph_count
Script.update_counters chapter.script_id, :paragaraphs_count => 1
end
def decrement_script_paragraph_count
Script.update_counters chapter.script_id, :paragaraphs_count => -1
end
end