<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,5 +1,7 @@
 *2.3.0/3.0*
 
+* Add :having as a key to find and the relevant associations.  [miloops]
+
 * Added default_scope to Base #1381 [Pawe&#322; Kondzior]. Example:
 
     class Person &lt; ActiveRecord::Base</diff>
      <filename>activerecord/CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -724,6 +724,8 @@ module ActiveRecord
       #   Specify second-order associations that should be eager loaded when the collection is loaded.
       # [:group]
       #   An attribute name by which the result should be grouped. Uses the &lt;tt&gt;GROUP BY&lt;/tt&gt; SQL-clause.
+      # [:having]
+      #   Combined with +:group+ this can be used to filter the records that a &lt;tt&gt;GROUP BY&lt;/tt&gt; returns. Uses the &lt;tt&gt;HAVING&lt;/tt&gt; SQL-clause.
       # [:limit]
       #   An integer determining the limit on the number of rows that should be returned.
       # [:offset]
@@ -1181,6 +1183,8 @@ module ActiveRecord
       #   Specify second-order associations that should be eager loaded when the collection is loaded.
       # [:group]
       #   An attribute name by which the result should be grouped. Uses the &lt;tt&gt;GROUP BY&lt;/tt&gt; SQL-clause.
+      # [:having]
+      #   Combined with +:group+ this can be used to filter the records that a &lt;tt&gt;GROUP BY&lt;/tt&gt; returns. Uses the &lt;tt&gt;HAVING&lt;/tt&gt; SQL-clause.
       # [:limit]
       #   An integer determining the limit on the number of rows that should be returned.
       # [:offset]
@@ -1553,7 +1557,7 @@ module ActiveRecord
         @@valid_keys_for_has_many_association = [
           :class_name, :table_name, :foreign_key, :primary_key,
           :dependent,
-          :select, :conditions, :include, :order, :group, :limit, :offset,
+          :select, :conditions, :include, :order, :group, :having, :limit, :offset,
           :as, :through, :source, :source_type,
           :uniq,
           :finder_sql, :counter_sql,
@@ -1609,7 +1613,7 @@ module ActiveRecord
         mattr_accessor :valid_keys_for_has_and_belongs_to_many_association
         @@valid_keys_for_has_and_belongs_to_many_association = [
           :class_name, :table_name, :join_table, :foreign_key, :association_foreign_key,
-          :select, :conditions, :include, :order, :group, :limit, :offset,
+          :select, :conditions, :include, :order, :group, :having, :limit, :offset,
           :uniq,
           :finder_sql, :counter_sql, :delete_sql, :insert_sql,
           :before_add, :after_add, :before_remove, :after_remove,
@@ -1658,7 +1662,7 @@ module ActiveRecord
           add_conditions!(sql, options[:conditions], scope)
           add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) &amp;&amp; ((scope &amp;&amp; scope[:limit]) || options[:limit])
 
-          add_group!(sql, options[:group], scope)
+          add_group!(sql, options[:group], options[:having], scope)
           add_order!(sql, options[:order], scope)
           add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
           add_lock!(sql, options, scope)
@@ -1714,7 +1718,7 @@ module ActiveRecord
           end
 
           add_conditions!(sql, options[:conditions], scope)
-          add_group!(sql, options[:group], scope)
+          add_group!(sql, options[:group], options[:having], scope)
 
           if order &amp;&amp; is_distinct
             connection.add_order_by_for_association_limiting!(sql, :order =&gt; order)</diff>
      <filename>activerecord/lib/active_record/associations.rb</filename>
    </modified>
    <modified>
      <diff>@@ -188,6 +188,7 @@ module ActiveRecord
         def merge_options_from_reflection!(options)
           options.reverse_merge!(
             :group   =&gt; @reflection.options[:group],
+            :having  =&gt; @reflection.options[:having],
             :limit   =&gt; @reflection.options[:limit],
             :offset  =&gt; @reflection.options[:offset],
             :joins   =&gt; @reflection.options[:joins],</diff>
      <filename>activerecord/lib/active_record/associations/association_proxy.rb</filename>
    </modified>
    <modified>
      <diff>@@ -521,6 +521,7 @@ module ActiveRecord #:nodoc:
       # * &lt;tt&gt;:conditions&lt;/tt&gt; - An SQL fragment like &quot;administrator = 1&quot;, &lt;tt&gt;[ &quot;user_name = ?&quot;, username ]&lt;/tt&gt;, or &lt;tt&gt;[&quot;user_name = :user_name&quot;, { :user_name =&gt; user_name }]&lt;/tt&gt;. See conditions in the intro.
       # * &lt;tt&gt;:order&lt;/tt&gt; - An SQL fragment like &quot;created_at DESC, name&quot;.
       # * &lt;tt&gt;:group&lt;/tt&gt; - An attribute name by which the result should be grouped. Uses the &lt;tt&gt;GROUP BY&lt;/tt&gt; SQL-clause.
+      # * &lt;tt&gt;:having&lt;/tt&gt; - Combined with +:group+ this can be used to filter the records that a &lt;tt&gt;GROUP BY&lt;/tt&gt; returns. Uses the &lt;tt&gt;HAVING&lt;/tt&gt; SQL-clause.
       # * &lt;tt&gt;:limit&lt;/tt&gt; - An integer determining the limit on the number of rows that should be returned.
       # * &lt;tt&gt;:offset&lt;/tt&gt; - An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.
       # * &lt;tt&gt;:joins&lt;/tt&gt; - Either an SQL fragment for additional joins like &quot;LEFT JOIN comments ON comments.post_id = id&quot; (rarely needed)
@@ -1632,7 +1633,7 @@ module ActiveRecord #:nodoc:
           add_joins!(sql, options[:joins], scope)
           add_conditions!(sql, options[:conditions], scope)
 
-          add_group!(sql, options[:group], scope)
+          add_group!(sql, options[:group], options[:having], scope)
           add_order!(sql, options[:order], scope)
           add_limit!(sql, options, scope)
           add_lock!(sql, options, scope)
@@ -1688,13 +1689,15 @@ module ActiveRecord #:nodoc:
           end
         end
 
-        def add_group!(sql, group, scope = :auto)
+        def add_group!(sql, group, having, scope = :auto)
           if group
             sql &lt;&lt; &quot; GROUP BY #{group}&quot;
+            sql &lt;&lt; &quot; HAVING #{having}&quot; if having
           else
             scope = scope(:find) if :auto == scope
             if scope &amp;&amp; (scoped_group = scope[:group])
               sql &lt;&lt; &quot; GROUP BY #{scoped_group}&quot;
+              sql &lt;&lt; &quot; HAVING #{scoped_having}&quot; if (scoped_having = scope[:having])
             end
           end
         end
@@ -2259,7 +2262,7 @@ module ActiveRecord #:nodoc:
         end
 
         VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset,
-                               :order, :select, :readonly, :group, :from, :lock ]
+                               :order, :select, :readonly, :group, :having, :from, :lock ]
 
         def validate_find_options(options) #:nodoc:
           options.assert_valid_keys(VALID_FIND_OPTIONS)</diff>
      <filename>activerecord/lib/active_record/base.rb</filename>
    </modified>
    <modified>
      <diff>@@ -658,6 +658,11 @@ class HasAndBelongsToManyAssociationsTest &lt; ActiveRecord::TestCase
     assert_equal 1, categories(:technology).posts_gruoped_by_title.size
   end
 
+  def test_find_scoped_grouped_having
+    assert_equal 2, projects(:active_record).well_payed_salary_groups.size
+    assert projects(:active_record).well_payed_salary_groups.all? { |g| g.salary &gt; 10000 }
+  end
+
   def test_get_ids
     assert_equal projects(:active_record, :action_controller).map(&amp;:id).sort, developers(:david).project_ids.sort
     assert_equal [projects(:active_record).id], developers(:jamis).project_ids</diff>
      <filename>activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -255,6 +255,11 @@ class HasManyAssociationsTest &lt; ActiveRecord::TestCase
     assert_equal 2, companies(:first_firm).clients_grouped_by_name.length
   end
 
+  def test_find_scoped_grouped_having
+    assert_equal 1, authors(:david).popular_grouped_posts.length
+    assert_equal 0, authors(:mary).popular_grouped_posts.length
+  end
+
   def test_adding
     force_signal37_to_load_all_clients_of_firm
     natural = Client.new(&quot;name&quot; =&gt; &quot;Natural Company&quot;)</diff>
      <filename>activerecord/test/cases/associations/has_many_associations_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -175,6 +175,13 @@ class FinderTest &lt; ActiveRecord::TestCase
     assert_equal 4, developers.map(&amp;:salary).uniq.size
   end
 
+  def test_find_with_group_and_having
+    developers =  Developer.find(:all, :group =&gt; &quot;salary&quot;, :having =&gt; &quot;sum(salary) &gt;  10000&quot;, :select =&gt; &quot;salary&quot;)
+    assert_equal 3, developers.size
+    assert_equal 3, developers.map(&amp;:salary).uniq.size
+    assert developers.all? { |developer|  developer.salary &gt; 10000 }
+  end
+
   def test_find_with_entire_select_statement
     topics = Topic.find_by_sql &quot;SELECT * FROM topics WHERE author_name = 'Mary'&quot;
 </diff>
      <filename>activerecord/test/cases/finder_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,7 @@
 class Author &lt; ActiveRecord::Base
   has_many :posts
   has_many :posts_with_comments, :include =&gt; :comments, :class_name =&gt; &quot;Post&quot;
+  has_many :popular_grouped_posts, :include =&gt; :comments, :class_name =&gt; &quot;Post&quot;, :group =&gt; &quot;type&quot;, :having =&gt; &quot;SUM(comments_count) &gt; 1&quot;, :select =&gt; &quot;type&quot;
   has_many :posts_with_comments_sorted_by_comment_id, :include =&gt; :comments, :class_name =&gt; &quot;Post&quot;, :order =&gt; 'comments.id'
   has_many :posts_sorted_by_id_limited, :class_name =&gt; &quot;Post&quot;, :order =&gt; 'posts.id', :limit =&gt; 1
   has_many :posts_with_categories, :include =&gt; :categories, :class_name =&gt; &quot;Post&quot;</diff>
      <filename>activerecord/test/models/author.rb</filename>
    </modified>
    <modified>
      <diff>@@ -14,6 +14,7 @@ class Category &lt; ActiveRecord::Base
                           :class_name =&gt; 'Post',
                           :conditions =&gt; { :title =&gt; 'Yet Another Testing Title' }
 
+  has_and_belongs_to_many :popular_grouped_posts, :class_name =&gt; &quot;Post&quot;, :group =&gt; &quot;posts.type&quot;, :having =&gt; &quot;sum(comments.post_id) &gt; 2&quot;, :include =&gt; :comments
   has_and_belongs_to_many :posts_gruoped_by_title, :class_name =&gt; &quot;Post&quot;, :group =&gt; &quot;title&quot;, :select =&gt; &quot;title&quot;
 
   def self.what_are_you</diff>
      <filename>activerecord/test/models/category.rb</filename>
    </modified>
    <modified>
      <diff>@@ -13,6 +13,7 @@ class Project &lt; ActiveRecord::Base
                             :after_add =&gt; Proc.new {|o, r| o.developers_log &lt;&lt; &quot;after_adding#{r.id || '&lt;new&gt;'}&quot;},
                             :before_remove =&gt; Proc.new {|o, r| o.developers_log &lt;&lt; &quot;before_removing#{r.id}&quot;},
                             :after_remove =&gt; Proc.new {|o, r| o.developers_log &lt;&lt; &quot;after_removing#{r.id}&quot;}
+  has_and_belongs_to_many :well_payed_salary_groups, :class_name =&gt; &quot;Developer&quot;, :group =&gt; &quot;salary&quot;, :having =&gt; &quot;SUM(salary) &gt; 10000&quot;, :select =&gt; &quot;SUM(salary) as salary&quot;
 
   attr_accessor :developers_log
 </diff>
      <filename>activerecord/test/models/project.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>0c4ba90aa1ea6a8d386c724a55a31e63a13c46ab</id>
    </parent>
  </parents>
  <author>
    <name>miloops</name>
    <login></login>
    <email>miloops@gmail.com</email>
  </author>
  <url>http://github.com/rails/rails/commit/97403ad5fdfcdfb2110c6f8fd0ebf43b7afc4859</url>
  <id>97403ad5fdfcdfb2110c6f8fd0ebf43b7afc4859</id>
  <committed-date>2008-12-01T11:22:31-08:00</committed-date>
  <authored-date>2008-11-21T14:20:33-08:00</authored-date>
  <message>Add :having option to find, to use in combination with grouped finds. Also added to has_many and has_and_belongs_to_many associations.

Signed-off-by: Michael Koziarski &lt;michael@koziarski.com&gt;
[#1028 state:committed]</message>
  <tree>77998cf59255d49323d7f7063025ca895e162f62</tree>
  <committer>
    <name>Michael Koziarski</name>
    <login>NZKoz</login>
    <email>michael@koziarski.com</email>
  </committer>
</commit>
