Class: ActiveRecord::Associations::JoinDependency

Inherits:
Object
  • Object
show all
Defined in:
activerecord/lib/active_record/associations/join_dependency.rb,
activerecord/lib/active_record/associations/join_dependency/join_base.rb,
activerecord/lib/active_record/associations/join_dependency/join_part.rb,
activerecord/lib/active_record/associations/join_dependency/join_association.rb

Overview

:nodoc:

Defined Under Namespace

Classes: Aliases, JoinAssociation, JoinBase, JoinPart

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(base, table, associations, joins, eager_loading: true) ⇒ JoinDependency

base is the base class on which operation is taking place. associations is the list of associations which are joined using hash, symbol or array. joins is the list of all string join commands and arel nodes.

Example :

class Physician < ActiveRecord::Base
  has_many :appointments
  has_many :patients, through: :appointments
end

If I execute `@physician.patients.to_a` then
  base # => Physician
  associations # => []
  joins # =>  [#<Arel::Nodes::InnerJoin: ...]

However if I execute `Physician.joins(:appointments).to_a` then
  base # => Physician
  associations # => [:appointments]
  joins # =>  []


93
94
95
96
97
98
99
# File 'activerecord/lib/active_record/associations/join_dependency.rb', line 93

def initialize(base, table, associations, joins, eager_loading: true)
  @alias_tracker = AliasTracker.create_with_joins(base.connection, base.table_name, joins)
  @eager_loading = eager_loading
  tree = self.class.make_tree associations
  @join_root = JoinBase.new(base, table, build(tree, base))
  @join_root.children.each { |child| construct_tables! @join_root, child }
end

Instance Attribute Details

#alias_trackerObject (readonly)

Returns the value of attribute alias_tracker.



46
47
48
# File 'activerecord/lib/active_record/associations/join_dependency.rb', line 46

def alias_tracker
  @alias_tracker
end

#base_klassObject (readonly)

Returns the value of attribute base_klass.



46
47
48
# File 'activerecord/lib/active_record/associations/join_dependency.rb', line 46

def base_klass
  @base_klass
end

#join_rootObject (readonly)

Returns the value of attribute join_root.



46
47
48
# File 'activerecord/lib/active_record/associations/join_dependency.rb', line 46

def join_root
  @join_root
end

Class Method Details

.make_tree(associations) ⇒ Object



48
49
50
51
52
# File 'activerecord/lib/active_record/associations/join_dependency.rb', line 48

def self.make_tree(associations)
  hash = {}
  walk_tree associations, hash
  hash
end

.walk_tree(associations, hash) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'activerecord/lib/active_record/associations/join_dependency.rb', line 54

def self.walk_tree(associations, hash)
  case associations
  when Symbol, String
    hash[associations.to_sym] ||= {}
  when Array
    associations.each do |assoc|
      walk_tree assoc, hash
    end
  when Hash
    associations.each do |k, v|
      cache = hash[k] ||= {}
      walk_tree v, cache
    end
  else
    raise ConfigurationError, associations.inspect
  end
end

Instance Method Details

#aliasesObject



121
122
123
124
125
126
127
128
# File 'activerecord/lib/active_record/associations/join_dependency.rb', line 121

def aliases
  @aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i|
    columns = join_part.column_names.each_with_index.map { |column_name, j|
      Aliases::Column.new column_name, "t#{i}_r#{j}"
    }
    Aliases::Table.new(join_part, columns)
  }
end

#instantiate(result_set, &block) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'activerecord/lib/active_record/associations/join_dependency.rb', line 130

def instantiate(result_set, &block)
  primary_key = aliases.column_alias(join_root, join_root.primary_key)

  seen = Hash.new { |i, object_id|
    i[object_id] = Hash.new { |j, child_class|
      j[child_class] = {}
    }
  }

  model_cache = Hash.new { |h, klass| h[klass] = {} }
  parents = model_cache[join_root]
  column_aliases = aliases.column_aliases join_root

  message_bus = ActiveSupport::Notifications.instrumenter

  payload = {
    record_count: result_set.length,
    class_name: join_root.base_klass.name
  }

  message_bus.instrument("instantiation.active_record", payload) do
    result_set.each { |row_hash|
      parent_key = primary_key ? row_hash[primary_key] : row_hash
      parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, &block)
      construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases)
    }
  end

  parents.values
end

#join_constraints(joins_to_add, join_type) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'activerecord/lib/active_record/associations/join_dependency.rb', line 105

def join_constraints(joins_to_add, join_type)
  joins = join_root.children.flat_map { |child|
    make_join_constraints(join_root, child, join_type)
  }

  joins.concat joins_to_add.flat_map { |oj|
    if join_root.match? oj.join_root
      walk join_root, oj.join_root
    else
      oj.join_root.children.flat_map { |child|
        make_join_constraints(oj.join_root, child, join_type)
      }
    end
  }
end

#reflectionsObject



101
102
103
# File 'activerecord/lib/active_record/associations/join_dependency.rb', line 101

def reflections
  join_root.drop(1).map!(&:reflection)
end