Class: PassiveRecord::Associations::HasManyThroughRelation

Inherits:
HasManyRelation show all
Defined in:
lib/passive_record/associations/has_many_through.rb

Instance Attribute Summary

Attributes inherited from Relation

#association, #parent_model

Instance Method Summary collapse

Methods inherited from HasManyRelation

#method_missing, #singular?

Methods included from PassiveRecord::ArithmeticHelpers

#average, #mode, #pluck, #sum

Methods inherited from HasOneRelation

#child_class, #child_class_name, #id, #lookup, #lookup_or_create, #parent_model_id_field

Methods inherited from Relation

#singular?

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class PassiveRecord::Associations::HasManyRelation

Instance Method Details

#<<(child) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/passive_record/associations/has_many_through.rb', line 15

def <<(child)
  if nested_association.is_a?(HasManyAssociation)
    intermediary_id =
      child.send(association.base_association.target_name_symbol.to_s.singularize + "_id")

    if intermediary_id
      intermediary_relation.child_class.find(intermediary_id).
        send(:"#{parent_model_id_field}=", parent_model.id)
    else
      nested_ids_field = nested_association.children_name_sym.to_s.singularize + "_ids"
      intermediary_model = intermediary_relation.singular? ?
          intermediary_relation.lookup_or_create :
          intermediary_relation.where(parent_model_id_field => parent_model.id).first_or_create

      intermediary_model.update(
          nested_ids_field => intermediary_model.send(nested_ids_field) + [ child.id ]
        )
    end
  else
    intermediary_model = intermediary_relation.
      where(
        association.target_name_symbol.to_s.singularize + "_id" => child.id).
        first_or_create
  end
  self
end

#allObject



67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/passive_record/associations/has_many_through.rb', line 67

def all
  join_results = intermediate_results
  if intermediate_results && !join_results.empty?
    final_results = join_results.flat_map(&nested_association.target_name_symbol)
    if final_results.first.is_a?(Associations::Relation)
      final_results.flat_map(&:all)
    else
      Array(final_results)
    end
  else
    []
  end
end

#create(attrs = {}) ⇒ Object



42
43
44
45
46
# File 'lib/passive_record/associations/has_many_through.rb', line 42

def create(attrs={})
  child = child_class.create(attrs)
  send(:<<, child)
  child
end

#intermediary_conditionsObject



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/passive_record/associations/has_many_through.rb', line 93

def intermediary_conditions
  intermediary_key = if intermediary_relation.association.is_a?(HasManyAssociation)
                       intermediary_relation.association.children_name_sym.to_s.singularize.to_sym
                     elsif intermediary_relation.association.is_a?(HasManyThroughAssociation)
                       intermediary_relation.association.through_class.to_s.singularize.to_sym
                     else 
                       raise "Intermediary association #{intermediary_relation.association} is not has many or has many through...?"
                     end
  
  nested_conds = { intermediary_key => { parent_model_id_field.to_sym => parent_model.id } }

  if nested_association.is_a?(HasManyThroughAssociation)
    n = nested_association
    hash = nested_conds

    until !n.is_a?(HasManyThroughAssociation)
      key = n.through_class.to_s.singularize.to_sym
      hash = {key => hash}
      n = n.nested_association
    end

    hash
  else
    nested_conds
  end
end

#intermediary_relationObject



81
82
83
# File 'lib/passive_record/associations/has_many_through.rb', line 81

def intermediary_relation
  @intermediary_relation ||= association.base_association.to_relation(parent_model)
end

#intermediate_resultsObject



85
86
87
88
89
90
91
# File 'lib/passive_record/associations/has_many_through.rb', line 85

def intermediate_results
  if intermediary_relation.singular?
    Array(intermediary_relation.lookup)
  else
    intermediary_relation.all
  end
end

#nested_associationObject



55
56
57
58
59
60
61
62
63
64
65
# File 'lib/passive_record/associations/has_many_through.rb', line 55

def nested_association
  nested_class.associations.detect { |assn|
    assn.child_class_name == association.child_class_name ||
    assn.child_class_name == association.child_class_name.singularize ||

    (assn.parent_class_name == association.child_class_name rescue false) ||
    (assn.parent_class_name == association.child_class_name.singularize rescue false) ||

    assn.target_name_symbol == association.target_name_symbol.to_s.singularize.to_sym
  }
end

#nested_classObject



48
49
50
51
52
53
# File 'lib/passive_record/associations/has_many_through.rb', line 48

def nested_class
  module_name = association.parent_class.name.deconstantize
  module_name = "Object" if module_name.empty?
  (module_name.constantize).
    const_get("#{association.base_association.child_class_name.singularize}")
end

#where(conditions = {}) ⇒ Object



120
121
122
# File 'lib/passive_record/associations/has_many_through.rb', line 120

def where(conditions={})
  child_class.where(conditions.merge(intermediary_conditions))
end