From ea759cb76161a7a0003c3cd3b38a8a125a99af3c Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 7 Dec 2004 12:25:01 +0000 Subject: Added counter_sql option for has_many associations [bitsweat] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@68 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activerecord/lib/active_record/associations.rb | 4 +++- .../active_record/associations/has_many_association.rb | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index b015699fba..b83ce831c7 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -166,6 +166,8 @@ module ActiveRecord # May not be set if :dependent is also set. # * :finder_sql - specify a complete SQL statement to fetch the association. This is a good way to go for complex # associations that depends on multiple tables. Note: When this option is used, +find_in_collection+ is _not_ added. + # * :counter_sql - specify a complete SQL statement to fetch the size of the association. If +:finder_sql+ is + # specified but +:counter_sql+, +:counter_sql+ will be generated by replacing SELECT ... FROM with SELECT COUNT(*) FROM. # # Option examples: # has_many :comments, :order => "posted_on" @@ -177,7 +179,7 @@ module ActiveRecord # 'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' + # 'ORDER BY p.first_name' def has_many(association_id, options = {}) - validate_options([ :foreign_key, :class_name, :exclusively_dependent, :dependent, :conditions, :order, :finder_sql ], options.keys) + validate_options([ :foreign_key, :class_name, :exclusively_dependent, :dependent, :conditions, :order, :finder_sql, :counter_sql ], options.keys) association_name, association_class_name, association_class_primary_key_name = associate_identification(association_id, options[:class_name], options[:foreign_key]) diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 947862ad37..0f2d20d240 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -7,9 +7,15 @@ module ActiveRecord if options[:finder_sql] @finder_sql = interpolate_sql(options[:finder_sql]) - @counter_sql = @finder_sql.gsub(/SELECT (.*) FROM/i, "SELECT COUNT(*) FROM") else - @finder_sql = "#{@association_class_primary_key_name} = '#{@owner.id}' #{@conditions ? " AND " + interpolate_sql(@conditions) : ""}" + @finder_sql = "#{@association_class_primary_key_name} = '#{@owner.id}' #{@conditions ? " AND " + interpolate_sql(@conditions) : ""}" + end + + if options[:counter_sql] + @counter_sql = interpolate_sql(options[:counter_sql]) + elsif options[:finder_sql] + @counter_sql = options[:counter_sql] = @finder_sql.gsub(/SELECT (.*) FROM/i, "SELECT COUNT(*) FROM") + else @counter_sql = "#{@association_class_primary_key_name} = '#{@owner.id}'#{@conditions ? " AND " + interpolate_sql(@conditions) : ""}" end end @@ -70,21 +76,21 @@ module ActiveRecord @association_class.find_all(@finder_sql, @options[:order] ? @options[:order] : nil) end end - + def count_records if has_cached_counter? @owner.send(:read_attribute, cached_counter_attribute_name) - elsif @options[:finder_sql] + elsif @options[:counter_sql] @association_class.count_by_sql(@counter_sql) else @association_class.count(@counter_sql) end end - + def has_cached_counter? @owner.attribute_present?(cached_counter_attribute_name) end - + def cached_counter_attribute_name "#{@association_name}_count" end -- cgit v1.2.3