diff options
Diffstat (limited to 'activerecord/lib/active_record/associations/join_dependency')
-rw-r--r-- | activerecord/lib/active_record/associations/join_dependency/join_association.rb | 51 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/join_dependency/join_part.rb | 1 |
2 files changed, 31 insertions, 21 deletions
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb index 84e18684d8..c1ef86a95b 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb @@ -21,11 +21,15 @@ module ActiveRecord super && reflection == other.reflection end + JoinInformation = Struct.new :joins, :binds + def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain) joins = [] + bind_values = [] tables = tables.reverse - scope_chain_iter = scope_chain.reverse_each + scope_chain_index = 0 + scope_chain = scope_chain.reverse # The chain starts with the target table, but we want to end with it here (makes # more sense in this context), so we reverse @@ -33,48 +37,55 @@ module ActiveRecord table = tables.shift klass = reflection.klass - case reflection.source_macro - when :belongs_to - key = reflection.association_primary_key - foreign_key = reflection.foreign_key - else - key = reflection.foreign_key - foreign_key = reflection.active_record_primary_key - end + join_keys = reflection.join_keys(klass) + key = join_keys.key + foreign_key = join_keys.foreign_key constraint = build_constraint(klass, table, key, foreign_table, foreign_key) - scope_chain_items = scope_chain_iter.next.map do |item| + predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table)) + scope_chain_items = scope_chain[scope_chain_index].map do |item| if item.is_a?(Relation) item else - ActiveRecord::Relation.create(klass, table).instance_exec(node, &item) + ActiveRecord::Relation.create(klass, table, predicate_builder) + .instance_exec(node, &item) end end + scope_chain_index += 1 - if reflection.type - scope_chain_items << - ActiveRecord::Relation.create(klass, table) - .where(reflection.type => foreign_klass.base_class.name) - end - - scope_chain_items.concat [klass.send(:build_default_scope)].compact + relation = ActiveRecord::Relation.create( + klass, + table, + predicate_builder, + ) + scope_chain_items.concat [klass.send(:build_default_scope, relation)].compact rel = scope_chain_items.inject(scope_chain_items.shift) do |left, right| left.merge right end if rel && !rel.arel.constraints.empty? + bind_values.concat rel.bind_values constraint = constraint.and rel.arel.constraints end + if reflection.type + value = foreign_klass.base_class.name + column = klass.columns_hash[reflection.type.to_s] + + substitute = klass.connection.substitute_at(column) + bind_values.push [column, value] + constraint = constraint.and table[reflection.type].eq substitute + end + joins << table.create_join(table, table.create_on(constraint), join_type) # The current table in this iteration becomes the foreign table in the next foreign_table, foreign_klass = table, klass end - joins + JoinInformation.new joins, bind_values end # Builds equality condition. @@ -86,7 +97,7 @@ module ActiveRecord # end # # If I execute `Physician.joins(:appointments).to_a` then - # reflection # => #<ActiveRecord::Reflection::AssociationReflection @macro=:has_many ...> + # klass # => Physician # table # => #<Arel::Table @name="appointments" ...> # key # => physician_id # foreign_table # => #<Arel::Table @name="physicians" ...> diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb index 91e1c6a9d7..9c6573f913 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb @@ -19,7 +19,6 @@ module ActiveRecord def initialize(base_klass, children) @base_klass = base_klass - @column_names_with_alias = nil @children = children end |