From bf165a49431f83e48b1660e96db0746537101a78 Mon Sep 17 00:00:00 2001 From: John Wulff Date: Tue, 17 Mar 2009 16:42:36 -0700 Subject: [PATCH] added new option to has_many association: association_condition allowing default "primary_key = foreign_key" condition to be overridden to something more complex like "primary_key LIKE foreign_key" or "SQL_FUNCTION(primary_key, foreign_key)" --- activerecord/lib/active_record/associations.rb | 7 ++++++- .../associations/has_many_association.rb | 4 ++++ .../associations/has_many_associations_test.rb | 6 ++++++ activerecord/test/cases/reflection_test.rb | 4 ++-- activerecord/test/models/company.rb | 2 ++ 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 6d25b36..d71aeca 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -775,6 +775,10 @@ module ActiveRecord # If false, don't validate the associated objects when saving the parent object. true by default. # [:autosave] # If true, always save any loaded members and destroy members marked for destruction, when saving the parent object. Off by default. + # [:association_condition] + # Specifies the SQL condition that should be used to associate records. + # has_many :comments_mentioning, :class_name => 'Comment', :association_condition => 'comments.body LIKE "%#{name}%"' will look + # for all Comments whose body is LIKE the name attribute on the source model. # # Option examples: # has_many :comments, :order => "posted_on" @@ -1466,7 +1470,8 @@ module ActiveRecord :finder_sql, :counter_sql, :before_add, :after_add, :before_remove, :after_remove, :extend, :readonly, - :validate + :validate, + :association_condition ] def create_has_many_reflection(association_id, options, &extension) diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index a2cbabf..0d1c89a 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -92,6 +92,10 @@ module ActiveRecord "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}" @finder_sql << " AND (#{conditions})" if conditions + when @reflection.options[:association_condition] + @finder_sql = interpolate_sql @reflection.options[:association_condition] + @finder_sql << " AND (#{conditions})" if conditions + else @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}" @finder_sql << " AND (#{conditions})" if conditions diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 30edf79..bb80d1a 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -1058,5 +1058,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase client = firm.clients_using_primary_key.create!(:name => 'test') assert_equal firm.name, client.firm_name end + + def test_finding_using_association_condition + company = Company.find 4 + returned_ids = company.comments_using_association_condition_even_ids_not_same_id.collect{ |x| x.id } + assert_equal [ 2, 6, 8, 10 ], returned_ids.sort + end end diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index db64bbb..9275c9a 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -170,8 +170,8 @@ class ReflectionTest < ActiveRecord::TestCase def test_reflection_of_all_associations # FIXME these assertions bust a lot - assert_equal 28, Firm.reflect_on_all_associations.size - assert_equal 21, Firm.reflect_on_all_associations(:has_many).size + assert_equal 29, Firm.reflect_on_all_associations.size + assert_equal 22, Firm.reflect_on_all_associations(:has_many).size assert_equal 7, Firm.reflect_on_all_associations(:has_one).size assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index 02a775f..6678198 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -62,6 +62,8 @@ class Firm < Company has_many :readonly_clients, :class_name => 'Client', :readonly => true has_many :clients_using_primary_key, :class_name => 'Client', :primary_key => 'name', :foreign_key => 'firm_name' + has_many :comments_using_association_condition_even_ids_not_same_id, :class_name => 'Comment', + :association_condition => 'comments.id % 2 = 0 AND comments.id != #{id}' has_many :clients_grouped_by_firm_id, :class_name => "Client", :group => "firm_id", :select => "firm_id" has_many :clients_grouped_by_name, :class_name => "Client", :group => "name", :select => "name" -- 1.5.6