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

Parameters:

  • association_name (String, Symbol)

    Association name that identifies a relationship with other objects.

Returns:

  • (QuerySet, nil)

    QuerySet based on the association_name, nil if the relationship is not found.



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

Parameters:

  • association_name (String, Symbol)

    Association name that identifies a relationship with other object.

Returns:

  • (QuerySet, nil)

    QuerySet based on the association_name, nil if the relationship is not found.



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.

Parameters:

  • selection_path (String, Symbol, nil) (defaults to: nil)

    Path of relationships that will be used as filter. If nil, a QuerySet with the current object selected will be returned. Otherwise, a QuerySet with the selection

    described by the __ and

    operators.

Returns:

  • (QuerySet)

    QuerySet for the selection_path passed as parameter.



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

Parameters:

  • selection_path (String) (defaults to: nil)

    Association name whose objects we want to return.

Returns:

  • (QuerySet)

    QuerySet with the foreign objects filtered by this 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