Forum: Ruby on Rails adding custom cache field

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
D449d54c3b0f8c9930c11c7d7d3e6cdd?d=identicon&s=25 Surendra Singhi (Guest)
on 2006-03-13 20:55
(Received via mailing list)
Hello,
 I needed to add custom cache field for one of my application. I thought
I
will share the code showing how to do this.

This code below creates and maintain a custom cache field, for keeping
track
of totals. Say, you have accounts, and for each account there are
transactions
(either deposit/withdrawal), and one will like to keep track of the
total
balance for an account.

So, let there be a transactions table with the field 'amount' for which
we want
to keep track of the total. Then in the accounts table, we will need the
field, 'transactions_total'.

And while declaring the models just add the line,

belongs_to_extra :accounts, :total_cache => :amount

This code below is tested with edge rail, and will work for polymorphic
associations also.

Any comments are welcome.

 module ActiveRecord
  module Associations # :nodoc:
    def self.append_features(base)
      super
      base.extend(ClassMethods)
    end

    module ClassMethods

      def belongs_to_extra(association_id, options = { })
        association_type = association_id.to_s + "_type" if
association_id
        association_primary_key = association_id.to_s + "_id"
        if options[:total_cache]
          module_eval(
                      "after_create
'#{association_type}.constantize.modify_value(\"#{self.to_s.underscore.pluralize
+ "_total"}\",#{association_primary_key},#{options[:total_cache]})" +
                      " unless #{association_type}.nil?'"
                      )
          module_eval(
                      "before_update
'#{association_type}.constantize.modify_value(\"#{self.to_s.underscore.pluralize
+ "_total"}\",#{association_primary_key},#{options[:total_cache]} -
#{self}.find(id).#{options[:total_cache]})" +
                      " unless #{association_type}.nil?'")

          module_eval(
                      "before_destroy
'#{association_type}.constantize.modify_value(\"#{self.to_s.underscore.pluralize
+
"_total"}\",#{association_primary_key}_type,-#{options[:total_cache]})"
+
                      " unless #{association_type}.nil?'"
                      )

        end
      end
    end

    class AssociationCollection
      def total
        count = if has_cached_total?
                  @owner.send(:read_attribute,cached_total_attribute_name)
                end
      end
      def has_cached_total?
        @owner.attribute_present?(cached_total_attribute_name)
      end
      def cached_total_attribute_name
          "#{@reflection.name}_total"
      end
    end
  end
end

module ActiveRecord #:nodoc:
  class Base
    class << self # Class methods
      def modify_value(total_name, id, value)
        update_all "#{total_name} = #{total_name} + #{value}",
"#{primary_key} = #{quote(id)}"
      end
    end
  end
end

--
Surendra Singhi
http://ssinghi.kreeti.com, http://www.kreeti.com
Read my blog at: http://cuttingtheredtape.blogspot.com/
,----
| "All animals are equal, but some animals are more equal than others."
|     -- Orwell, Animal Farm, 1945
`----
This topic is locked and can not be replied to.