= CalculatedAttribute Here's the scenario: you've got a few nice, normalized database tables: invoices, line_items, and payments. Your Invoice model has a method that calculates the amount due, by adding up the line items and payments, and comparing them. It works fine for small data sets, but what if you want to display the total due for 500 invoices? Slow as molasses. The :include option helps with the n+1 queries problem, but Ruby still has to do quite a bit of crunching. And if you want to find only those invoices with a balance due? The database can't help -- you have to load it all, and let Rails separate the wheat from the chaff. The answer is denormalization. But it can be tricky to get right, and you don't want to clutter your models with code to handle all the details. This Rails plugin provides a new class method for ActiveRecord, +calculated_attr+. It allows you to cache the value of a block to a column in the database, and have the value automatically re-cached when the model or its associations change. For example: class Invoice < ActiveRecord::Base has_many :line_items has_many :payments # expects a 'subtotal' column in the 'invoices' table calculated_attr :subtotal, :dependent => [ :line_items ] do line_items.inject(0) { |sum, line| sum + line.total } end # expects a 'paid' column in the 'invoices' table calculated_attr :paid, :dependent => [ :payments ] do payments.inject(0) { |sum, payment| sum + payment.total } end # expects a 'total' column in the 'invoices' table calculated_attr :total, :dependent => [ :line_items ] do subtotal + tax end # expects a 'due' column in the 'invoices' table calculated_attr :due, :dependent => [ :line_items, :payments ] do total - paid end end i = Invoice.new; i.line_items << LineItem.new(:total => 10) i.save # calculates the value of 'subtotal' and saves it to the invoices table i = Invoice.find :first, :conditions => "subtotal=10" i.subtotal # returns the cached value; no need to load line items i.line_items << LineItem.new(:total => 5) # re-calculates and saves the subtotal Now, whenever the model is saved or validated, or associations are added or removed, the attributes are re-calculated and saved in the attributes hash. From then on, the attribute accessors use the cached values, rather than the expensive computation. Saving the model causes the calculated attributes to be stored in the database, so they can be used in queries. See the API documentation for full details. == Resources Install:: gem install calculated_attribute Rubyforge project:: http://rubyforge.org/projects/calculated_attribute/ RDocs:: http://calculated-attribute.rubyforge.org/ Subversion:: http://redgreenblu.com/svn/projects/calculated_attribute/ == Author Scott Raymond . Extracted from Blinksale.com, the easiest way to send invoices online. == License Copyright 2006 Scott Raymond, released under the MIT license.