<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1164,6 +1164,9 @@ module ActiveRecord
       #   If true, duplicate associated objects will be ignored by accessors and query methods.
       # [:finder_sql]
       #   Overwrite the default generated SQL statement used to fetch the association with a manual statement
+      # [:counter_sql]
+      #   Specify a complete SQL statement to fetch the size of the association. If &lt;tt&gt;:finder_sql&lt;/tt&gt; is
+      #   specified but not &lt;tt&gt;:counter_sql&lt;/tt&gt;, &lt;tt&gt;:counter_sql&lt;/tt&gt; will be generated by replacing &lt;tt&gt;SELECT ... FROM&lt;/tt&gt; with &lt;tt&gt;SELECT COUNT(*) FROM&lt;/tt&gt;.
       # [:delete_sql]
       #   Overwrite the default generated SQL statement used to remove links between the associated
       #   classes with a manual statement.</diff>
      <filename>activerecord/lib/active_record/associations.rb</filename>
    </modified>
    <modified>
      <diff>@@ -128,6 +128,35 @@ module ActiveRecord
         end
       end
 
+      # Count all records using SQL. If the +:counter_sql+ option is set for the association, it will
+      # be used for the query. If no +:counter_sql+ was supplied, but +:finder_sql+ was set, the
+      # descendant's +construct_sql+ method will have set :counter_sql automatically.
+      # Otherwise, construct options and pass them with scope to the target class's +count+.
+      def count(*args)
+        if @reflection.options[:counter_sql]
+          @reflection.klass.count_by_sql(@counter_sql)
+        else
+          column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args)
+          if @reflection.options[:uniq]
+            # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
+            column_name = &quot;#{@reflection.quoted_table_name}.#{@reflection.klass.primary_key}&quot; if column_name == :all
+            options.merge!(:distinct =&gt; true)
+          end
+
+          value = @reflection.klass.send(:with_scope, construct_scope) { @reflection.klass.count(column_name, options) }
+
+          limit  = @reflection.options[:limit]
+          offset = @reflection.options[:offset]
+
+          if limit || offset
+            [ [value - offset.to_i, 0].max, limit.to_i ].min
+          else
+            value
+          end
+        end
+      end
+
+
       # Remove +records+ from this association.  Does not destroy +records+.
       def delete(*records)
         records = flatten_deeper(records)</diff>
      <filename>activerecord/lib/active_record/associations/association_collection.rb</filename>
    </modified>
    <modified>
      <diff>@@ -78,6 +78,16 @@ module ActiveRecord
           end
 
           @join_sql = &quot;INNER JOIN #{@owner.connection.quote_table_name @reflection.options[:join_table]} ON #{@reflection.quoted_table_name}.#{@reflection.klass.primary_key} = #{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.association_foreign_key}&quot;
+
+          if @reflection.options[:counter_sql]
+            @counter_sql = interpolate_sql(@reflection.options[:counter_sql])
+          elsif @reflection.options[:finder_sql]
+            # replace the SELECT clause with COUNT(*), preserving any hints within /* ... */
+            @reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { &quot;SELECT #{$1}COUNT(*) FROM&quot; }
+            @counter_sql = interpolate_sql(@reflection.options[:counter_sql])
+          else
+            @counter_sql = @finder_sql
+          end
         end
 
         def construct_scope</diff>
      <filename>activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,32 +1,6 @@
 module ActiveRecord
   module Associations
     class HasManyAssociation &lt; AssociationCollection #:nodoc:
-      # Count the number of associated records. All arguments are optional.
-      def count(*args)
-        if @reflection.options[:counter_sql]
-          @reflection.klass.count_by_sql(@counter_sql)
-        elsif @reflection.options[:finder_sql]
-          @reflection.klass.count_by_sql(@finder_sql)
-        else
-          column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args)          
-          options[:conditions] = options[:conditions].blank? ?
-            @finder_sql :
-            @finder_sql + &quot; AND (#{sanitize_sql(options[:conditions])})&quot;
-          options[:include] ||= @reflection.options[:include]
-
-          value = @reflection.klass.count(column_name, options)
-
-          limit  = @reflection.options[:limit]
-          offset = @reflection.options[:offset]
-
-          if limit || offset
-            [ [value - offset.to_i, 0].max, limit.to_i ].min
-          else
-            value
-          end
-        end
-      end
-
       protected
         def owner_quoted_id
           if @reflection.options[:primary_key]</diff>
      <filename>activerecord/lib/active_record/associations/has_many_association.rb</filename>
    </modified>
    <modified>
      <diff>@@ -31,16 +31,6 @@ module ActiveRecord
         return count
       end
       
-      def count(*args)
-        column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args)
-        if @reflection.options[:uniq]
-          # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL statement.
-          column_name = &quot;#{@reflection.quoted_table_name}.#{@reflection.klass.primary_key}&quot; if column_name == :all
-          options.merge!(:distinct =&gt; true) 
-        end
-        @reflection.klass.send(:with_scope, construct_scope) { @reflection.klass.count(column_name, options) } 
-      end
-
       protected
         def construct_find_options!(options)
           options[:select]  = construct_select(options[:select])</diff>
      <filename>activerecord/lib/active_record/associations/has_many_through_association.rb</filename>
    </modified>
    <modified>
      <diff>@@ -703,4 +703,11 @@ class HasAndBelongsToManyAssociationsTest &lt; ActiveRecord::TestCase
     # due to Unknown column 'authors.id'
     assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog')
   end
+
+  def test_counting_on_habtm_association_and_not_array
+    david = Developer.find(1)
+    # Extra parameter just to make sure we aren't falling back to
+    # Array#count in Ruby &gt;=1.8.7, which would raise an ArgumentError
+    assert_nothing_raised { david.projects.count(:all, :conditions =&gt; '1=1') }
+  end
 end</diff>
      <filename>activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>ce4d13861dc54a1ac7fbe411327b9a2427f95366</id>
    </parent>
  </parents>
  <author>
    <name>Ernie Miller</name>
    <email>ernie@metautonomo.us</email>
  </author>
  <url>http://github.com/rails/rails/commit/44af2efa2c7391681968c827ca47201a0a02e974</url>
  <id>44af2efa2c7391681968c827ca47201a0a02e974</id>
  <committed-date>2008-08-28T11:58:25-07:00</committed-date>
  <authored-date>2008-08-28T11:01:42-07:00</authored-date>
  <message>Refactored AssociationCollection#count for uniformity and Ruby 1.8.7 support.

[#831 state:resolved]

Signed-off-by: Jeremy Kemper &lt;jeremy@bitsweat.net&gt;</message>
  <tree>a25ede2a88799c281468fcdaa4321d6048cee240</tree>
  <committer>
    <name>Jeremy Kemper</name>
    <email>jeremy@bitsweat.net</email>
  </committer>
</commit>
