aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations/through_association_scope.rb
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2010-10-02 18:50:17 +0100
committerJon Leighton <j@jonathanleighton.com>2010-10-02 18:50:17 +0100
commit34ee586e993ad9e466b81f376fa92feb5d312b4c (patch)
tree5ab70bda381aeb9f068d970a517801ebd06f8e49 /activerecord/lib/active_record/associations/through_association_scope.rb
parent4f69a61107d9d59f96bf249ef077483e90babe72 (diff)
downloadrails-34ee586e993ad9e466b81f376fa92feb5d312b4c.tar.gz
rails-34ee586e993ad9e466b81f376fa92feb5d312b4c.tar.bz2
rails-34ee586e993ad9e466b81f376fa92feb5d312b4c.zip
Integrate nested support into ThroughAssociationScope, using my concept of generating a 'chain' of reflections to be joined. It seems to work at the moment, all existing tests are passing. There may be further complications as we add more test cases for nested associations, though.
Diffstat (limited to 'activerecord/lib/active_record/associations/through_association_scope.rb')
-rw-r--r--activerecord/lib/active_record/associations/through_association_scope.rb89
1 files changed, 53 insertions, 36 deletions
diff --git a/activerecord/lib/active_record/associations/through_association_scope.rb b/activerecord/lib/active_record/associations/through_association_scope.rb
index c433c9e66e..c5453fa79f 100644
--- a/activerecord/lib/active_record/associations/through_association_scope.rb
+++ b/activerecord/lib/active_record/associations/through_association_scope.rb
@@ -1,3 +1,5 @@
+require 'enumerator'
+
module ActiveRecord
# = Active Record Through Association Scope
module Associations
@@ -19,8 +21,9 @@ module ActiveRecord
# Build SQL conditions from attributes, qualified by table name.
def construct_conditions
- table_name = @reflection.final_through_reflection.quoted_table_name
- conditions = construct_quoted_owner_attributes(@reflection.final_through_reflection).map do |attr, value|
+ reflection = @reflection.through_reflection_chain.last
+ table_name = reflection.quoted_table_name
+ conditions = construct_quoted_owner_attributes(reflection).map do |attr, value|
"#{table_name}.#{attr} = #{value}"
end
conditions << sql_conditions if sql_conditions
@@ -51,43 +54,57 @@ module ActiveRecord
end
def construct_joins(custom_joins = nil)
- "#{construct_through_joins(@reflection)} #{@reflection.options[:joins]} #{custom_joins}"
+ # puts @reflection.through_reflection_chain.map(&:inspect)
+
+ "#{construct_through_joins} #{@reflection.options[:joins]} #{custom_joins}"
end
- def construct_through_joins(reflection)
- polymorphic_join = nil
- if reflection.source_reflection.macro == :belongs_to
- reflection_primary_key = reflection.klass.primary_key
- source_primary_key = reflection.source_reflection.primary_key_name
- if reflection.options[:source_type]
- polymorphic_join = "AND %s.%s = %s" % [
- reflection.through_reflection.quoted_table_name, "#{@reflection.source_reflection.options[:foreign_type]}",
- @owner.class.quote_value(reflection.options[:source_type])
- ]
- end
- else
- reflection_primary_key = reflection.source_reflection.primary_key_name
- source_primary_key = reflection.through_reflection.klass.primary_key
- if reflection.source_reflection.options[:as]
- polymorphic_join = "AND %s.%s = %s" % [
- reflection.quoted_table_name, "#{@reflection.source_reflection.options[:as]}_type",
- @owner.class.quote_value(reflection.through_reflection.klass.name)
- ]
- end
- end
-
- joins = "INNER JOIN %s ON %s.%s = %s.%s %s" % [
- reflection.through_reflection.quoted_table_name,
- reflection.quoted_table_name, reflection_primary_key,
- reflection.through_reflection.quoted_table_name, source_primary_key,
- polymorphic_join
- ]
+ def construct_through_joins
+ joins = []
- # If the reflection we are going :through goes itself :through another reflection, then
- # we must recursively get the joins to make that happen too.
- if reflection.through_reflection.through_reflection
- joins << " "
- joins << construct_through_joins(reflection.through_reflection)
+ # Iterate over each pair in the through reflection chain, joining them together
+ @reflection.through_reflection_chain.each_cons(2) do |left, right|
+ polymorphic_join = nil
+
+ case
+ when left.options[:as]
+ left_primary_key = left.primary_key_name
+ right_primary_key = right.klass.primary_key
+
+ polymorphic_join = "AND %s.%s = %s" % [
+ left.quoted_table_name, "#{left.options[:as]}_type",
+ @owner.class.quote_value(right.klass.name)
+ ]
+ when left.source_reflection.macro == :belongs_to
+ left_primary_key = left.klass.primary_key
+ right_primary_key = left.source_reflection.primary_key_name
+
+ if left.options[:source_type]
+ polymorphic_join = "AND %s.%s = %s" % [
+ right.quoted_table_name,
+ left.source_reflection.options[:foreign_type].to_s,
+ @owner.class.quote_value(left.options[:source_type])
+ ]
+ end
+ else
+ left_primary_key = left.source_reflection.primary_key_name
+ right_primary_key = right.klass.primary_key
+
+ if left.source_reflection.options[:as]
+ polymorphic_join = "AND %s.%s = %s" % [
+ left.quoted_table_name,
+ "#{left.source_reflection.options[:as]}_type",
+ @owner.class.quote_value(right.klass.name)
+ ]
+ end
+ end
+
+ joins << "INNER JOIN %s ON %s.%s = %s.%s %s" % [
+ right.quoted_table_name,
+ left.quoted_table_name, left_primary_key,
+ right.quoted_table_name, right_primary_key,
+ polymorphic_join
+ ]
end
joins