Skip to content

Commit

Permalink
Refactor ThroughAssociation#join_to to be much smaller, and independe…
Browse files Browse the repository at this point in the history
…nt of construct_owner_conditions.
  • Loading branch information
jonleighton committed Mar 6, 2011
1 parent d02c326 commit 5dc1fb3
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 84 deletions.
112 changes: 28 additions & 84 deletions activerecord/lib/active_record/associations/through_association.rb
Expand Up @@ -28,7 +28,6 @@ def target_scope


def association_scope def association_scope
scope = join_to(super) scope = join_to(super)
scope = scope.where(reflection_conditions(0))


unless options[:include] unless options[:include]
scope = scope.includes(source_options[:include]) scope = scope.includes(source_options[:include])
Expand Down Expand Up @@ -57,95 +56,42 @@ def aliased_through_table
end end


def construct_owner_conditions def construct_owner_conditions
super(tables.last, through_reflection_chain.last)
end end


def join_to(scope) def join_to(scope)
joins = [] joins = []
tables = tables().dup # FIXME: Ugly tables = tables().dup # FIXME: Ugly


foreign_reflection = through_reflection_chain.first through_reflection_chain.each_with_index do |reflection, i|
foreign_table = tables.shift table, foreign_table = tables.shift, tables.first


through_reflection_chain[1..-1].each_with_index do |reflection, i| if reflection.source_macro == :has_and_belongs_to_many
i += 1 join_table = tables.shift
table = tables.shift

joins << inner_join(
if foreign_reflection.source_reflection.nil? join_table,
case foreign_reflection.macro table[reflection.active_record_primary_key].
when :belongs_to eq(join_table[reflection.association_foreign_key])
joins << inner_join( )
table,
foreign_table[foreign_reflection.association_primary_key], table, foreign_table = join_table, tables.first
table[foreign_reflection.foreign_key], end
reflection_conditions(i)
) if reflection.source_macro == :belongs_to
when :has_many, :has_one key = reflection.association_primary_key
joins << inner_join( foreign_key = reflection.foreign_key
table,
foreign_table[foreign_reflection.foreign_key],
table[reflection.association_primary_key],
reflection_conditions(i)
)
when :has_and_belongs_to_many
join_table = foreign_table

joins << inner_join(
table,
join_table[foreign_reflection.foreign_key],
table[reflection.klass.primary_key],
reflection_conditions(i)
)
end
else else
case foreign_reflection.source_reflection.macro key = reflection.foreign_key
when :belongs_to foreign_key = reflection.association_primary_key
joins << inner_join(
table,
foreign_table[foreign_reflection.association_primary_key],
table[foreign_reflection.foreign_key],
reflection_conditions(i)
)
when :has_many, :has_one
joins << inner_join(
table,
foreign_table[foreign_reflection.foreign_key],
table[foreign_reflection.source_reflection.active_record_primary_key],
reflection_conditions(i)
)

if reflection.macro == :has_and_belongs_to_many
join_table = tables.shift

joins << inner_join(
join_table,
table[reflection.klass.primary_key],
join_table[reflection.association_foreign_key]
)

# hack to make it become the foreign_table
table = join_table
end
when :has_and_belongs_to_many
join_table, table = table, tables.shift

joins << inner_join(
join_table,
foreign_table[foreign_reflection.klass.primary_key],
join_table[foreign_reflection.association_foreign_key]
)

joins << inner_join(
table,
join_table[foreign_reflection.foreign_key],
table[reflection.klass.primary_key],
reflection_conditions(i)
)
end
end end


foreign_reflection = reflection if reflection == through_reflection_chain.last
foreign_table = table constraint = table[key].eq owner[foreign_key]
scope = scope.where(constraint).where(reflection_conditions(i))
else
constraint = table[key].eq foreign_table[foreign_key]
joins << inner_join(foreign_table, constraint, reflection_conditions(i))
end
end end


scope.joins(joins) scope.joins(joins)
Expand Down Expand Up @@ -221,9 +167,7 @@ def table_alias_for(reflection, join = false)
name name
end end


def inner_join(table, left_column, right_column, *conditions) def inner_join(table, *conditions)
conditions << left_column.eq(right_column)

table.create_join( table.create_join(
table, table,
table.create_on(table.create_and(conditions.flatten.compact))) table.create_on(table.create_and(conditions.flatten.compact)))
Expand Down
6 changes: 6 additions & 0 deletions activerecord/lib/active_record/reflection.rb
Expand Up @@ -279,6 +279,8 @@ def source_reflection
nil nil
end end


alias :source_macro :macro

def has_inverse? def has_inverse?
@options[:inverse_of] @options[:inverse_of]
end end
Expand Down Expand Up @@ -474,6 +476,10 @@ def through_conditions
end end
end end


def source_macro
source_reflection.source_macro
end

# A through association is nested iff there would be more than one join table # A through association is nested iff there would be more than one join table
def nested? def nested?
through_reflection_chain.length > 2 || through_reflection_chain.length > 2 ||
Expand Down

0 comments on commit 5dc1fb3

Please sign in to comment.