Class: ActiveRecord::Associations::Preloader::Branch

Inherits:
Object
  • Object
show all
Defined in:
activerecord/lib/active_record/associations/preloader/branch.rb

Overview

:nodoc:

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(association:, children:, parent:, associate_by_default:, scope:) ⇒ Branch

Returns a new instance of Branch.


11
12
13
14
15
16
17
18
19
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 11

def initialize(association:, children:, parent:, associate_by_default:, scope:)
  @association = association
  @parent = parent
  @scope = scope
  @associate_by_default = associate_by_default

  @children = build_children(children)
  @loaders = nil
end

Instance Attribute Details

#associate_by_defaultObject (readonly)

Returns the value of attribute associate_by_default.


8
9
10
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 8

def associate_by_default
  @associate_by_default
end

#associationObject (readonly)

Returns the value of attribute association.


7
8
9
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 7

def association
  @association
end

#childrenObject (readonly)

Returns the value of attribute children.


7
8
9
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 7

def children
  @children
end

#parentObject (readonly)

Returns the value of attribute parent.


7
8
9
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 7

def parent
  @parent
end

#preloaded_recordsObject


62
63
64
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 62

def preloaded_records
  @preloaded_records ||= loaders.flat_map(&:preloaded_records)
end

#scopeObject (readonly)

Returns the value of attribute scope.


8
9
10
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 8

def scope
  @scope
end

Instance Method Details

#done?Boolean

Returns:

  • (Boolean)

66
67
68
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 66

def done?
  root? || (@loaders && @loaders.all?(&:run?))
end

#future_classesObject


21
22
23
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 21

def future_classes
  (immediate_future_classes + children.flat_map(&:future_classes)).uniq
end

#grouped_recordsObject


74
75
76
77
78
79
80
81
82
83
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 74

def grouped_records
  h = {}
  polymorphic_parent = !root? && parent.polymorphic?
  source_records.each do |record|
    reflection = record.class._reflect_on_association(association)
    next if polymorphic_parent && !reflection || !record.association(association).klass
    (h[reflection] ||= []) << record
  end
  h
end

#immediate_future_classesObject


25
26
27
28
29
30
31
32
33
34
35
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 25

def immediate_future_classes
  if parent.done?
    loaders.flat_map(&:future_classes).uniq
  else
    likely_reflections.reject(&:polymorphic?).flat_map do |reflection|
      reflection.
        chain.
        map(&:klass)
    end.uniq
  end
end

#likely_reflectionsObject


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

def likely_reflections
  parent_classes = parent.target_classes
  parent_classes.filter_map do |parent_klass|
    parent_klass._reflect_on_association(@association)
  end
end

#loadersObject


112
113
114
115
116
117
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 112

def loaders
  @loaders ||=
    grouped_records.flat_map do |reflection, reflection_records|
      preloaders_for_reflection(reflection, reflection_records)
    end
end

#polymorphic?Boolean

Returns:

  • (Boolean)

102
103
104
105
106
107
108
109
110
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 102

def polymorphic?
  return false if root?
  return @polymorphic if defined?(@polymorphic)

  @polymorphic = source_records.any? do |record|
    reflection = record.class._reflect_on_association(association)
    reflection && reflection.options[:polymorphic]
  end
end

#preloaders_for_reflection(reflection, reflection_records) ⇒ Object


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 85

def preloaders_for_reflection(reflection, reflection_records)
  reflection_records.group_by do |record|
    klass = record.association(association).klass

    if reflection.scope && reflection.scope.arity != 0
      # For instance dependent scopes, the scope is potentially
      # different for each record. To allow this we'll group each
      # object separately into its own preloader
      reflection_scope = reflection.join_scopes(klass.arel_table, klass.predicate_builder, klass, record).inject(&:merge!)
    end

    [klass, reflection_scope]
  end.map do |(rhs_klass, reflection_scope), rs|
    preloader_for(reflection).new(rhs_klass, rs, reflection, scope, reflection_scope, associate_by_default)
  end
end

#root?Boolean

Returns:

  • (Boolean)

54
55
56
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 54

def root?
  parent.nil?
end

#runnable_loadersObject


70
71
72
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 70

def runnable_loaders
  loaders.flat_map(&:runnable_loaders).reject(&:run?)
end

#source_recordsObject


58
59
60
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 58

def source_records
  @parent.preloaded_records
end

#target_classesObject


37
38
39
40
41
42
43
44
45
# File 'activerecord/lib/active_record/associations/preloader/branch.rb', line 37

def target_classes
  if done?
    preloaded_records.map(&:klass).uniq
  elsif parent.done?
    loaders.map(&:klass).uniq
  else
    likely_reflections.reject(&:polymorphic?).map(&:klass).uniq
  end
end