module Babik::InstanceMethods

All instance methods that are injected to ActiveRecord models

Public Instance Methods

_objects_direct_has_many(association_name) click to toggle source

@!method _objects_direct_has_many(association_name) Return a QuerySet with a direct relationship to many @param [String, Symbol] association_name Association name that identifies a relationship with other objects. @return [QuerySet, nil] QuerySet based on the association_name, nil if the relationship is not found.

# 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) click to toggle source

@!method _objects_to_one(association_name) Return a QuerySet with the relationship to one @param [String, Symbol] association_name Association name that identifies a relationship with other object. @return [QuerySet, nil] QuerySet based on the association_name, nil if the relationship is not found.

# 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) click to toggle source

@!method _objects_with_selection_path(selection_path = nil) Return a QuerySet following the passed selection path. @param [String, Symbol, nil] selection_path 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.

@return [QuerySet] QuerySet for the selection_path passed as parameter.

# 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) click to toggle source

@!method objects(selection_path = nil) Get a queryset that contains the foreign model filtered by the current instance @param [String] selection_path Association name whose objects we want to return. @return [QuerySet] QuerySet with the foreign objects filtered by this instance.

# 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