diff options
author | wycats <wycats@gmail.com> | 2010-05-09 02:06:05 +0300 |
---|---|---|
committer | wycats <wycats@gmail.com> | 2010-05-09 02:37:52 +0300 |
commit | d916c62cfc7c59ab6411407a05b946d3dd7535e9 (patch) | |
tree | 653ac4017ea6af4520dd9e6f60d846e19d5e3074 /activerecord/lib/active_record/counter_cache.rb | |
parent | 636ffa1f089a51c98fce616191846eaba93d7b87 (diff) | |
download | rails-d916c62cfc7c59ab6411407a05b946d3dd7535e9.tar.gz rails-d916c62cfc7c59ab6411407a05b946d3dd7535e9.tar.bz2 rails-d916c62cfc7c59ab6411407a05b946d3dd7535e9.zip |
eliminate alias_method_chain from ActiveRecord
Diffstat (limited to 'activerecord/lib/active_record/counter_cache.rb')
-rw-r--r-- | activerecord/lib/active_record/counter_cache.rb | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb new file mode 100644 index 0000000000..cbebded995 --- /dev/null +++ b/activerecord/lib/active_record/counter_cache.rb @@ -0,0 +1,107 @@ +module ActiveRecord + module CounterCache + # Resets one or more counter caches to their correct value using an SQL + # count query. This is useful when adding new counter caches, or if the + # counter has been corrupted or modified directly by SQL. + # + # ==== Parameters + # + # * +id+ - The id of the object you wish to reset a counter on. + # * +counters+ - One or more counter names to reset + # + # ==== Examples + # + # # For Post with id #1 records reset the comments_count + # Post.reset_counters(1, :comments) + def reset_counters(id, *counters) + object = find(id) + counters.each do |association| + child_class = reflect_on_association(association).klass + counter_name = child_class.reflect_on_association(self.name.downcase.to_sym).counter_cache_column + + connection.update("UPDATE #{quoted_table_name} SET #{connection.quote_column_name(counter_name)} = #{object.send(association).count} WHERE #{connection.quote_column_name(primary_key)} = #{quote_value(object.id)}", "#{name} UPDATE") + end + end + + # A generic "counter updater" implementation, intended primarily to be + # used by increment_counter and decrement_counter, but which may also + # be useful on its own. It simply does a direct SQL update for the record + # with the given ID, altering the given hash of counters by the amount + # given by the corresponding value: + # + # ==== Parameters + # + # * +id+ - The id of the object you wish to update a counter on or an Array of ids. + # * +counters+ - An Array of Hashes containing the names of the fields + # to update as keys and the amount to update the field by as values. + # + # ==== Examples + # + # # For the Post with id of 5, decrement the comment_count by 1, and + # # increment the action_count by 1 + # Post.update_counters 5, :comment_count => -1, :action_count => 1 + # # Executes the following SQL: + # # UPDATE posts + # # SET comment_count = comment_count - 1, + # # action_count = action_count + 1 + # # WHERE id = 5 + # + # # For the Posts with id of 10 and 15, increment the comment_count by 1 + # Post.update_counters [10, 15], :comment_count => 1 + # # Executes the following SQL: + # # UPDATE posts + # # SET comment_count = comment_count + 1, + # # WHERE id IN (10, 15) + def update_counters(id, counters) + updates = counters.inject([]) { |list, (counter_name, increment)| + sign = increment < 0 ? "-" : "+" + list << "#{connection.quote_column_name(counter_name)} = COALESCE(#{connection.quote_column_name(counter_name)}, 0) #{sign} #{increment.abs}" + }.join(", ") + + if id.is_a?(Array) + ids_list = id.map {|i| quote_value(i)}.join(', ') + condition = "IN (#{ids_list})" + else + condition = "= #{quote_value(id)}" + end + + update_all(updates, "#{connection.quote_column_name(primary_key)} #{condition}") + end + + # Increment a number field by one, usually representing a count. + # + # This is used for caching aggregate values, so that they don't need to be computed every time. + # For example, a DiscussionBoard may cache post_count and comment_count otherwise every time the board is + # shown it would have to run an SQL query to find how many posts and comments there are. + # + # ==== Parameters + # + # * +counter_name+ - The name of the field that should be incremented. + # * +id+ - The id of the object that should be incremented. + # + # ==== Examples + # + # # Increment the post_count column for the record with an id of 5 + # DiscussionBoard.increment_counter(:post_count, 5) + def increment_counter(counter_name, id) + update_counters(id, counter_name => 1) + end + + # Decrement a number field by one, usually representing a count. + # + # This works the same as increment_counter but reduces the column value by 1 instead of increasing it. + # + # ==== Parameters + # + # * +counter_name+ - The name of the field that should be decremented. + # * +id+ - The id of the object that should be decremented. + # + # ==== Examples + # + # # Decrement the post_count column for the record with an id of 5 + # DiscussionBoard.decrement_counter(:post_count, 5) + def decrement_counter(counter_name, id) + update_counters(id, counter_name => -1) + end + end +end
\ No newline at end of file |