123456789_123456789_123456789_123456789_123456789_

Class: Mongoid::Association::Referenced::HasManyThrough

Overview

Metadata class for has_many :through associations.

Constant Summary

::Mongoid::Association::Relatable - Included

PRIMARY_KEY_DEFAULT, SHARED_OPTIONS

Instance Attribute Summary

::Mongoid::Association::Relatable - Included

#destructive?

Whether the dependent method is destructive.

#in_to?

Is this association an embedded_in or belongs_to association?

#many?

Is this association an embeds_many or has_many association?

#many_to_many?

Is this association a many-to-many association? Such an association stores its foreign keys as an array on the document itself.

#name

The name of the association.

#one?

Is this association an embeds_one or has_one association?

#options

The options on this association.

#owner_class

The class that owns this association.

#parent_inclusions

The associations above this one in the inclusion tree.

#parent_inclusions=

The associations above this one in the inclusion tree.

#validate?

Whether the associated object(s) should be validated.

::Mongoid::Association::Options - Included

#autobuilding?

Whether the association is autobuilding.

#autosave

::Mongoid::Association::Options to save any loaded members and destroy members that are marked for destruction when the parent object is saved.

#autosave?

Alias for Options#autosave.

#cascading_callbacks?

Whether the association has callbacks cascaded down from the parent.

#counter_cached?

Whether the association is counter-cached.

#cyclic?

Is the association cyclic.

#fallback

Invokes the :fallback Proc and returns the null object that stands in for the association when its actual value is nil.

#fallback?

Whether the association has a :fallback (null object) option set.

#forced_nil_inverse?

Whether the association has forced nil inverse (So no foreign keys are saved).

#indexed?

Whether to index the primary or foreign key field.

#polymorphic?

Whether this association is polymorphic.

#touchable?

Whether the association object should be automatically touched when its inverse object is updated.

Instance Method Summary

::Mongoid::Association::Relatable - Included

#==

Compare this association to another.

#bindable?

Whether trying to bind an object using this association should raise an error.

#class_name
#counter_cache_column_name

Get the counter cache column name.

#create_relation

Create an association proxy object using the owner and target.

#extension

Get the extension.

#foreign_key_check

Get the name of the method to check if the foreign key has changed.

#foreign_key_setter

The name of the foreign key setter method.

#get_callbacks

Get the callbacks for a given type.

#initialize

Initialize the ::Mongoid::Association.

#inverse

Get the inverse name.

#inverse_association

Get the inverse's association metadata.

#inverse_class

The class of the object owning this association.

#inverse_class_name

The class name of the object owning this association.

#inverse_klass
#inverse_setter

The name of the inverse setter method.

#inverse_type

Get the inverse type.

#inverse_type_setter

Gets the setter for the field that sets the type of document on a polymorphic association.

#inverses

Get the inverse names.

#key

The foreign key field if this association stores a foreign key.

#klass
#path

The atomic path for this association.

#relation_class

The class of the association object(s).

#relation_class_name
The class name, possibly unqualified or

prefixed, of the association object(s).

#setter

The name of the setter on this object for assigning an associated object.

#type_setter

Get the type setter.

#create_extension!, #default_inverse, #define_autosaver!, #define_builder!, #define_counter_cache_callbacks!, #define_creator!, #define_dependency!, #define_existence_check!, #define_getter!, #define_ids_getter!, #define_ids_setter!, #define_setter!, #define_touchable!,
#inverse_association_classes

Gets the model classes with inverse associations of this model.

#namespace_hierarchy

Returns an array of classes/modules forming the namespace hierarchy where symbols referenced in the provided class/module would be looked up by Ruby.

#polymorph!,
#resolve_name

Resolves the given class/module name in the context of the specified module, as Ruby would when a constant is referenced in the source.

#setup_index!, #validate!

::Mongoid::Association::Options - Included

#as

Returns the name of the parent to a polymorphic child.

#dependent

Specify what happens to the associated object when the owner is destroyed.

#inverse_of

The name the owning object uses to refer to this association.

#order

The custom sorting options on the association.

#primary_key

::Mongoid assumes that the field used to hold the primary key of the association is id.

#store_as

The store_as option.

#touch_field

The field for saving the associated object's type.

#type

The field for saving the associated object's type.

::Mongoid::Association::Constrainable - Included

#convert_to_foreign_key

Convert the supplied object to the appropriate type to set as the foreign key for an association.

#convert_polymorphic

Instance Attribute Details

#embedded?false (readonly)

Is this association embedded?

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 43

def embedded?
  false
end

#stores_foreign_key?false (readonly)

Through associations never store a foreign key on the owner document.

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 57

def stores_foreign_key?
  false
end

Instance Method Details

#criteria(base) ⇒ Mongoid::Criteria

Return a ::Mongoid::Criteria scoped to the target documents reachable from base via the through association. Performs two queries: one against the intermediate collection, one against the source collection.

Parameters:

  • base (Document)

    The owner document.

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 117

def criteria(base)
  through_crit = through_association.criteria(base)

  crit = if source_association.stores_foreign_key?
           # FK is on the intermediate (e.g. appointment.patient_id -> belongs_to :patient)
           target_pk = source_association.primary_key # '_id' on Patient
           source_fk = source_association.foreign_key # 'patient_id' on Appointment
           source_association.klass.where(
             target_pk => { '$in' => key_values(through_crit, source_fk) }
           )
         else
           # FK is on the source (e.g. reader.book_id -> has_many :readers on Book)
           source_pk = source_association.primary_key # '_id' on intermediate (Book)
           source_fk = source_association.foreign_key # 'book_id' on Reader
           source_association.klass.where(
             source_fk => { '$in' => key_values(through_crit, source_pk) }
           )
         end
  order ? crit.order_by(order) : crit
end

#default_primary_key (private)

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 195

def default_primary_key
  PRIMARY_KEY_DEFAULT
end

#define_readonly_setter! (private)

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 188

def define_readonly_setter!
  assoc = self
  @owner_class.re_define_method(:"#{name}=") do |_object|
    raise Mongoid::Errors::ReadonlyAssociation.new(self.class, assoc)
  end
end

#define_through_getter! (private)

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 169

def define_through_getter!
  assoc = self
  assoc_name = name
  @owner_class.re_define_method(assoc_name) do |reload = false|
    if reload || !instance_variable_defined?("@_#{assoc_name}")
      set_relation(assoc_name, HasManyThrough::Proxy.new(self, assoc))
    end
    instance_variable_get("@_#{assoc_name}")
  end
end

#define_through_ids_getter! (private)

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 180

def define_through_ids_getter!
  assoc_name = name
  ids_method = :"#{assoc_name.to_s.singularize}_ids"
  @owner_class.re_define_method(ids_method) do
    send(assoc_name).pluck(:_id)
  end
end

#key_values(criteria, key) ⇒ Array<Object> (private)

Pluck the given key from the criteria, dropping intermediates that have no value for it. A nil in an $in array matches every document whose queried field is null or absent, which would return documents outside the association. An empty result correctly matches nothing. Mirrors what the eager loader does.

Parameters:

Returns:

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 157

def key_values(criteria, key)
  criteria.pluck(key).compact.uniq
end

#relationClass

The proxy class for this association type.

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 50

def relation
  Proxy
end

#relation_complementsArray

The list of association complements.

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 28

def relation_complements
  [].freeze
end

#setup!self

Setup instance methods on the owner class.

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 35

def setup!
  setup_instance_methods!
  self
end

#setup_instance_methods! (private)

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 161

def setup_instance_methods!
  define_through_getter!
  define_through_ids_getter!
  define_readonly_setter!
  define_existence_check!
  self
end

#source_associationMongoid::Association::Relatable

The source association metadata on the intermediate class. Resolved lazily to allow forward references.

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 89

def source_association
  @source_association ||= begin
    source_name = (@options[:source] || name.to_s.singularize).to_s
    assoc = through_association.klass.relations[source_name] ||
            raise(
              Errors::InvalidRelationOption.new(
                @owner_class, name, :source, source_name
              )
            )
    if assoc.is_a?(Referenced::HasAndBelongsToMany)
      raise(
        Errors::InvalidRelationOption.new(
          @owner_class, name, :source,
          'has_and_belongs_to_many is not supported as a :through source'
        )
      )
    end
    assoc
  end
end

#through_associationMongoid::Association::Relatable

The intermediate association metadata on the owner class. Resolved lazily to allow forward references.

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 65

def through_association
  @through_association ||= begin
    assoc = @owner_class.relations[@options[:through].to_s] ||
            raise(
              Errors::InvalidRelationOption.new(
                @owner_class, name, :through, @options[:through]
              )
            )
    if assoc.embedded?
      raise(
        Errors::InvalidRelationOption.new(
          @owner_class, name, :through,
          'through association must be a referenced association, not embedded'
        )
      )
    end
    assoc
  end
end

#validation_defaultfalse

The default for validating the association object.

[ GitHub ]

  
# File 'lib/mongoid/association/referenced/has_many_through.rb', line 141

def validation_default
  false
end