Class: ActiveRecord::Associations::JoinDependency

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

Overview

:nodoc:

Defined Under Namespace

Classes: Aliases, JoinAssociation, JoinBase, JoinPart

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(base, table, associations, alias_tracker) ⇒ 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 # =>  []


91
92
93
94
95
96
# File 'lib/active_record/associations/join_dependency.rb', line 91

def initialize(base, table, associations, alias_tracker)
  @alias_tracker = alias_tracker
  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

Class Method Details

.make_tree(associations) ⇒ Object



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

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

.walk_tree(associations, hash) ⇒ Object



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

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



118
119
120
121
122
123
124
125
# File 'lib/active_record/associations/join_dependency.rb', line 118

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



127
128
129
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
# File 'lib/active_record/associations/join_dependency.rb', line 127

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



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/active_record/associations/join_dependency.rb', line 102

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



98
99
100
# File 'lib/active_record/associations/join_dependency.rb', line 98

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