Class: ApiMaker::PreloaderThrough

Inherits:
Object
  • Object
show all
Defined in:
lib/api_maker/preloader_through.rb

Instance Method Summary collapse

Constructor Details

#initialize(collection:, reflection:) ⇒ PreloaderThrough

Returns a new instance of PreloaderThrough.



2
3
4
5
# File 'lib/api_maker/preloader_through.rb', line 2

def initialize(collection:, reflection:)
  @collection = collection
  @reflection = reflection
end

Instance Method Details

#append_name_for_current_reflection(current_reflection) ⇒ Object



55
56
57
58
59
60
61
62
63
# File 'lib/api_maker/preloader_through.rb', line 55

def append_name_for_current_reflection(current_reflection)
  singular_name = current_reflection.__send__(:inverse_name)&.to_s || current_reflection.active_record.model_name.param_key
  return singular_name.to_sym if @reflection.klass.reflections.key?(singular_name)

  plural_name = singular_name.pluralize
  return plural_name.to_sym if @reflection.klass.reflections.key?(plural_name)

  raise "Couldn't find a reflection name #{singular_name} or #{plural_name} on #{@reflection.klass.name}"
end

#joins_array_to_hash(array) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/api_maker/preloader_through.rb', line 65

def joins_array_to_hash(array)
  array = array.clone

  result = {}
  work_result = result

  while array.any?
    element = array.pop

    if array.length == 1
      work_result[element] = array.pop
    else
      work_result[element] = {}
    end

    work_result = work_result[element]
  end

  result
end

#joins_for_reflection(current_reflection) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/api_maker/preloader_through.rb', line 24

def joins_for_reflection(current_reflection)
  joins = []

  loop do
    # Resolve if the through relationship is through multiple other through relationships
    current_reflection = resolve_through(current_reflection)

    macro = current_reflection.through_reflection.macro
    inverse_name = current_reflection.through_reflection.__send__(:inverse_name)

    if inverse_name
      joins << inverse_name
    elsif macro == :has_many
      joins << current_reflection.through_reflection.name
    elsif macro == :belongs_to || macro == :has_one
      joins << current_reflection.through_reflection.active_record.model_name.plural.to_sym
    else
      raise "Unknown class: #{current_reflection.through_reflection.class.name}"
    end

    current_reflection = next_reflection_for(current_reflection)

    unless current_reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
      joins.append(append_name_for_current_reflection(current_reflection))
      break
    end
  end

  joins
end

#models_query_through_reflectionObject



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/api_maker/preloader_through.rb', line 7

def models_query_through_reflection
  last_reflection = @reflection.through_reflection.inverse_of

  if last_reflection
    table_name = last_reflection.table_name
    primary_key = last_reflection.klass.primary_key
  else
    table_name = @reflection.through_reflection.active_record.model_name.plural
    primary_key = @reflection.through_reflection.active_record.primary_key
  end

  joins_hash = joins_array_to_hash(joins_for_reflection(@reflection))

  @reflection.klass.joins(joins_hash)
    .where(table_name => {primary_key => @collection.map(&:id)})
end

#next_reflection_for(current_reflection) ⇒ Object



86
87
88
89
90
91
92
93
94
95
# File 'lib/api_maker/preloader_through.rb', line 86

def next_reflection_for(current_reflection)
  reflection_name = (current_reflection.source_reflection_name || @reflection.name).to_s

  new_reflection = current_reflection.through_reflection.klass.reflections[reflection_name.pluralize]
  new_reflection ||= current_reflection.through_reflection.klass.reflections[reflection_name.singularize]

  raise "No such reflection: #{current_reflection.through_reflection.klass.name}##{reflection_name}" unless new_reflection

  new_reflection
end

#resolve_through(current_reflection) ⇒ Object



97
98
99
100
# File 'lib/api_maker/preloader_through.rb', line 97

def resolve_through(current_reflection)
  current_reflection = current_reflection.through_reflection while current_reflection.through_reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
  current_reflection
end