Module: Babik::InstanceMethods

Defined in:
lib/babik.rb

Overview

All instance methods that are injected to ActiveRecord models

Instance Method Summary collapse

Instance Method Details

#_objects_direct_has_many(association_name) ⇒ QuerySet?

Return a QuerySet with a direct relationship to many



92
93
94
95
96
97
98
99
100
101
102
# File 'lib/babik.rb', line 92

def _objects_direct_has_many(association_name)
  association = self.class.reflect_on_association(association_name.to_sym)
  return nil unless association
  target = Object.const_get(association.class_name)
  begin
    inverse_relationship = association.options.fetch(:inverse_of)
  rescue KeyError => _exception
    raise "Relationship #{association.name} of model #{self.class} has no inverse_of option."
  end
  target.objects.filter("#{inverse_relationship}#{Babik::Selection::Config::RELATIONSHIP_SEPARATOR}id": self.id)
end

#_objects_to_one(association_name) ⇒ QuerySet?

Return a QuerySet with the relationship to one



79
80
81
82
83
84
85
86
# File 'lib/babik.rb', line 79

def _objects_to_one(association_name)
  association_name_to_sym = association_name.to_sym
  association = self.class.reflect_on_association(association_name_to_sym)
  return nil unless association
  # If the relationship is belongs_to or has_one, return a lone ActiveRecord model
  return self.send(association_name_to_sym) if association.belongs_to? || association.has_one?
  nil
end

#_objects_with_selection_path(selection_path = nil) ⇒ QuerySet

Return a QuerySet following the passed selection path.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/babik.rb', line 43

def _objects_with_selection_path(selection_path = nil)
  # By default, a nil selection_path means the caller object wants to return a QuerySet with only itself
  return self.class.objects.filter(id: self.id) unless selection_path

  selection_path = selection_path.to_s
  is_a_selection_path = selection_path.include?(Babik::Selection::Config::RELATIONSHIP_SEPARATOR)
  return nil unless is_a_selection_path

  # If the selection path has more than one level deep, we have to build an instance-based query
  selection_path_parts = selection_path.split(Babik::Selection::Config::RELATIONSHIP_SEPARATOR)
  model_i = self.class

  # The aim is to reverse the selection_path both
  # - Relationships will come from target to source.
  # - Direction: the instance will become the filter.

  instance_selection_path_parts = []

  # For each selection path part, invert the association and construct a
  # new selection path for our instance-based query.
  selection_path_parts.each do |association_name_i|
    association_i = model_i.reflect_on_association(association_name_i.to_sym)
    inverse_association_name_i = association_i.options.fetch(:inverse_of)
    instance_selection_path_parts = [inverse_association_name_i] + instance_selection_path_parts
    model_i = association_i.klass
  end

  # Construct a new selection path for our instance-based query
  instance_selection_path = instance_selection_path_parts.join(Babik::Selection::Config::RELATIONSHIP_SEPARATOR)
  model_i.objects.filter("#{instance_selection_path}::id": self.id)
end

#objects(selection_path = nil) ⇒ QuerySet

Get a queryset that contains the foreign model filtered by the current instance



24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/babik.rb', line 24

def objects(selection_path = nil)
  # Instance based deep association
  instance_based_queryset = _objects_with_selection_path(selection_path)
  return instance_based_queryset if instance_based_queryset

  # Basic association to one (belongs_to and has_one)
  to_one_result = self._objects_to_one(selection_path)
  return to_one_result if to_one_result

  # has_many direct relationship (default case)
  self._objects_direct_has_many(selection_path)
end