Module: Mongoid::Association::Relatable
Relationships & Source Files | |
Extension / Inclusion / Inheritance Descendants | |
Included In:
| |
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
self,
Options ,
Constrainable
|
|
Defined in: | lib/mongoid/association/relatable.rb |
Overview
This module provides behaviors shared between ::Mongoid::Association
types.
Constant Summary
-
PRIMARY_KEY_DEFAULT =
The primary key default.
'_id'.freeze
-
SHARED_OPTIONS =
The options shared between all association types.
[ :class_name, :inverse_of, :validate, :extend ].freeze
Instance Attribute Summary
-
#destructive? ⇒ true | false
readonly
Whether the dependent method is destructive.
-
#in_to? ⇒ true | false
readonly
Is this association an embedded_in or belongs_to association?
-
#many? ⇒ true | false
readonly
Is this association an embeds_many or has_many association?
-
#name ⇒ Symbol
readonly
The name of the association.
-
#one? ⇒ true | false
readonly
Is this association an embeds_one or has_one association?
-
#options ⇒ Hash
readonly
The options on this association.
-
#parent_inclusions ⇒ Array<String>
rw
The associations above this one in the inclusion tree.
-
#parent_inclusions=(value) ⇒ Array<String>
rw
The associations above this one in the inclusion tree.
-
#validate? ⇒ true | false
readonly
Whether the associated object(s) should be validated.
Options
- Included
#autobuilding? | Whether the association is autobuilding. |
#autosave |
|
#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. |
#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
-
#==(other) ⇒ Object
Compare this association to another.
-
#bindable?(doc) ⇒ true | false
Whether trying to bind an object using this association should raise an error.
-
#class_name
Alias for #relation_class_name.
-
#counter_cache_column_name ⇒ String
Get the counter cache column name.
-
#create_relation(owner, target) ⇒ Proxy
Create an association proxy object using the owner and target.
-
#extension ⇒ Module
Get the extension.
-
#foreign_key_check ⇒ String
Get the name of the method to check if the foreign key has changed.
-
#foreign_key_setter ⇒ String
The name of the foreign key setter method.
-
#get_callbacks(callback_type) ⇒ Array<Proc | Symbol>
Get the callbacks for a given type.
-
#initialize(_class, name, opts = {}, &block)
Initialize the
::Mongoid::Association
. -
#inverse(other = nil) ⇒ Symbol
Get the inverse name.
-
#inverse_association(other = nil) ⇒ Mongoid::Association::Relatable
Get the inverse’s association metadata.
-
#inverse_class ⇒ String
(also: #inverse_klass)
The class of the object owning this association.
-
#inverse_class_name ⇒ String
The class name of the object owning this association.
-
#inverse_klass
Alias for #inverse_class.
-
#inverse_setter(other = nil) ⇒ String
The name of the inverse setter method.
-
#inverse_type ⇒ nil
Get the inverse type.
-
#inverse_type_setter ⇒ String
Gets the setter for the field that sets the type of document on a polymorphic association.
-
#inverses(other = nil) ⇒ Array<Symbol>
Get the inverse names.
-
#key ⇒ Symbol | String
The foreign key field if this association stores a foreign key.
-
#klass
Alias for #relation_class.
-
#path(document) ⇒ Mongoid::Atomic::Paths::Root
The atomic path for this association.
-
#relation_class ⇒ String
(also: #klass)
The class of the association object(s).
-
#relation_class_name ⇒ String
(also: #class_name)
- The class name, possibly unqualified or
prefixed, of the association object(s).
-
#setter ⇒ String
The name of the setter on this object for assigning an associated object.
-
#type_setter ⇒ String
Get the type setter.
- #create_extension!(&block) private
- #default_inverse private
- #define_autosaver! private
- #define_builder! private
- #define_counter_cache_callbacks! private
- #define_creator! private
- #define_dependency! private
- #define_existence_check! private
- #define_getter! private
- #define_ids_getter! private
- #define_ids_setter! private
- #define_setter! private
- #define_touchable! private
-
#inverse_association_classes
private
Gets the model classes with inverse associations of this model.
-
#namespace_hierarchy(mod)
private
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! private
-
#resolve_name(mod, name)
private
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! private
- #validate! private
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 |
|
#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. |
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
#destructive? ⇒ true
| false
(readonly)
Whether the dependent method is destructive.
# File 'lib/mongoid/association/relatable.rb', line 263
def destructive? @destructive ||= !!(dependent && (dependent == :delete_all || dependent == :destroy)) end
#in_to? ⇒ true
| false
(readonly)
Is this association an embedded_in or belongs_to association?
# File 'lib/mongoid/association/relatable.rb', line 333
def in_to? [Referenced::BelongsTo, Embedded::EmbeddedIn].any? { |a| self.is_a?(a) } end
#many? ⇒ true
| false
(readonly)
Is this association an embeds_many or has_many association?
# File 'lib/mongoid/association/relatable.rb', line 318
def many? [Referenced::HasMany, Embedded::EmbedsMany].any? { |a| self.is_a?(a) } end
#name ⇒ Symbol (readonly)
The name of the association.
# File 'lib/mongoid/association/relatable.rb', line 33
attr_reader :name
#one? ⇒ true
| false
(readonly)
Is this association an embeds_one or has_one association?
# File 'lib/mongoid/association/relatable.rb', line 325
def one? [Referenced::HasOne, Embedded::EmbedsOne].any? { |a| self.is_a?(a) } end
#options ⇒ Hash (readonly)
The options on this association.
# File 'lib/mongoid/association/relatable.rb', line 38
attr_reader :
#parent_inclusions ⇒ Array<String> (rw)
The associations above this one in the inclusion tree.
# File 'lib/mongoid/association/relatable.rb', line 311
attr_accessor :parent_inclusions
#parent_inclusions=(value) ⇒ Array<String> (rw)
The associations above this one in the inclusion tree.
# File 'lib/mongoid/association/relatable.rb', line 306
attr_accessor :parent_inclusions
#validate? ⇒ true
| false
(readonly)
Whether the associated object(s) should be validated.
# File 'lib/mongoid/association/relatable.rb', line 295
def validate? @validate ||= if @options[:validate].nil? validation_default else !!@options[:validate] end end
Instance Method Details
#==(other) ⇒ Object
Compare this association to another.
# File 'lib/mongoid/association/relatable.rb', line 62
def ==(other) relation_class_name == other.relation_class_name && inverse_class_name == other.inverse_class_name && name == other.name && == other. end
#bindable?(doc) ⇒ true
| false
Whether trying to bind an object using this association should raise an error.
# File 'lib/mongoid/association/relatable.rb', line 93
def bindable?(doc); false; end
#class_name
Alias for #relation_class_name.
# File 'lib/mongoid/association/relatable.rb', line 151
alias :class_name :relation_class_name
#counter_cache_column_name ⇒ String
Get the counter cache column name.
# File 'lib/mongoid/association/relatable.rb', line 270
def counter_cache_column_name @counter_cache_column_name ||= (@options[:counter_cache].is_a?(String) || @options[:counter_cache].is_a?(Symbol)) ? @options[:counter_cache] : "#{inverse || inverse_class_name.demodulize.underscore.pluralize}_count" end
#create_extension!(&block) (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 421
def create_extension!(&block) if block extension_module_name = "#{@owner_class.to_s.demodulize}#{name.to_s.camelize}RelationExtension" silence_warnings do @owner_class.const_set(extension_module_name, Module.new(&block)) end @extension = "#{@owner_class}::#{extension_module_name}".constantize end end
#create_relation(owner, target) ⇒ Proxy
Create an association proxy object using the owner and target.
# File 'lib/mongoid/association/relatable.rb', line 256
def create_relation(owner, target) relation.new(owner, target, self) end
#default_inverse (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 431
def default_inverse @default_inverse ||= klass.relations[inverse_klass.name.underscore] end
#define_autosaver! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 355
def define_autosaver! if autosave? Association::Referenced::AutoSave.define_autosave!(self) end end
#define_builder! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 361
def define_builder! Association::Builders.define_builder!(self) end
#define_counter_cache_callbacks! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 389
def define_counter_cache_callbacks! if counter_cached? Association::Referenced::CounterCache.define_callbacks!(self) end end
#define_creator! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 365
def define_creator! Association::Builders.define_creator!(self) end
#define_dependency! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 395
def define_dependency! if dependent Association::Depending.define_dependency!(self) end end
#define_existence_check! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 377
def define_existence_check! Association::Accessors.define_existence_check!(self) end
#define_getter! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 369
def define_getter! Association::Accessors.define_getter!(self) end
#define_ids_getter! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 381
def define_ids_getter! Association::Accessors.define_ids_getter!(self) end
#define_ids_setter! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 385
def define_ids_setter! Association::Accessors.define_ids_setter!(self) end
#define_setter! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 373
def define_setter! Association::Accessors.define_setter!(self) end
#define_touchable! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 349
def define_touchable! if touchable? Touchable.define_touchable!(self) end end
#extension ⇒ Module
Get the extension.
# File 'lib/mongoid/association/relatable.rb', line 279
def extension @extension ||= @options[:extend] end
#foreign_key_check ⇒ String
Get the name of the method to check if the foreign key has changed.
# File 'lib/mongoid/association/relatable.rb', line 245
def foreign_key_check @foreign_key_check ||= "#{foreign_key}_previously_changed?" if (stores_foreign_key? && foreign_key) end
#foreign_key_setter ⇒ String
The name of the foreign key setter method.
# File 'lib/mongoid/association/relatable.rb', line 215
def foreign_key_setter # note: You can't check if this association stores foreign key # See HasOne and HasMany binding, they referenced foreign_key_setter @foreign_key_setter ||= "#{foreign_key}=" if foreign_key end
#get_callbacks(callback_type) ⇒ Array<Proc
| Symbol>
Get the callbacks for a given type.
# File 'lib/mongoid/association/relatable.rb', line 75
def get_callbacks(callback_type) Array( [callback_type]) end
#initialize(_class, name, opts = {}, &block)
Initialize the ::Mongoid::Association
.
# File 'lib/mongoid/association/relatable.rb', line 46
def initialize(_class, name, opts = {}, &block) @owner_class = _class @name = name @options = opts @extension = nil @module_path = _class.name ? _class.name.split('::')[0..-2].join('::') : '' @module_path << '::' unless @module_path.empty? create_extension!(&block) validate! end
#inverse(other = nil) ⇒ Symbol
Get the inverse name.
# File 'lib/mongoid/association/relatable.rb', line 286
def inverse(other = nil) candidates = inverses(other) candidates.detect { |c| c } if candidates end
#inverse_association(other = nil) ⇒ Relatable
Get the inverse’s association metadata.
# File 'lib/mongoid/association/relatable.rb', line 118
def inverse_association(other = nil) (other || relation_class).relations[inverse(other)] end
#inverse_association_classes (private)
Gets the model classes with inverse associations of this model. This is used to determine the classes on the other end of polymorphic associations with models.
# File 'lib/mongoid/association/relatable.rb', line 341
def inverse_association_classes Mongoid::Config.models.map { |m| inverse_association(m) }.compact.map(&:inverse_class) end
#inverse_class ⇒ String Also known as: #inverse_klass
The class of the object owning this association.
# File 'lib/mongoid/association/relatable.rb', line 185
def inverse_class @owner_class end
#inverse_class_name ⇒ String
The class name of the object owning this association.
# File 'lib/mongoid/association/relatable.rb', line 178
def inverse_class_name @inverse_class_name ||= @owner_class.name end
#inverse_klass
Alias for #inverse_class.
# File 'lib/mongoid/association/relatable.rb', line 188
alias :inverse_klass :inverse_class
#inverse_setter(other = nil) ⇒ String
The name of the inverse setter method.
#inverse_type ⇒ nil
Get the inverse type.
# File 'lib/mongoid/association/relatable.rb', line 125
def inverse_type; end
#inverse_type_setter ⇒ String
Gets the setter for the field that sets the type of document on a polymorphic association.
# File 'lib/mongoid/association/relatable.rb', line 235
def inverse_type_setter @inverse_type_setter ||= "#{inverse_type}=" if inverse_type end
#inverses(other = nil) ⇒ Array<Symbol>
Get the inverse names.
# File 'lib/mongoid/association/relatable.rb', line 101
def inverses(other = nil) return [ inverse_of ] if inverse_of return [] if @options.key?(:inverse_of) && !inverse_of if polymorphic? polymorphic_inverses(other) else determine_inverses(other) end end
#key ⇒ Symbol | String
The foreign key field if this association stores a foreign key. Otherwise, the primary key.
# File 'lib/mongoid/association/relatable.rb', line 194
def key stores_foreign_key? ? foreign_key : primary_key end
#klass
Alias for #relation_class.
# File 'lib/mongoid/association/relatable.rb', line 173
alias :klass :relation_class
#namespace_hierarchy(mod) (private)
Returns an array of classes/modules forming the namespace hierarchy where symbols referenced in the provided class/module would be looked up by Ruby. For example, if mod is Foo::Bar, this method would return [Foo::Bar, Foo, Object].
#path(document) ⇒ Mongoid::Atomic::Paths::Root
The atomic path for this association.
# File 'lib/mongoid/association/relatable.rb', line 224
def path(document) relation.path(document) end
#polymorph! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 415
def polymorph! if polymorphic? @owner_class.polymorphic = true end end
#relation_class ⇒ String Also known as: #klass
The class of the association object(s).
This method returns the class instance corresponding to #relation_class_name, resolved relative to the host document class.
If the class does not exist, this method raises NameError. This can happen because the target class has not yet been defined. Note that polymorphic associations generally do not have a well defined target class because the target class can change from one object to another, and calling this method on a polymorphic association will generally fail with a NameError or produce misleading results (if a class does happen to be defined with the same name as the association name).
# File 'lib/mongoid/association/relatable.rb', line 167
def relation_class @klass ||= begin cls_name = @options[:class_name] || ActiveSupport::Inflector.classify(name) resolve_name(inverse_class, cls_name) end end
#relation_class_name ⇒ String Also known as: #class_name
The return value of this method should not be used to determine whether two associations have the same target class, because the return value is not always a fully qualified class name. To compare classes, retrieve the class instance of the association target using the #relation_class method.
- The class name, possibly unqualified or
-
prefixed, of the association
object(s).
This method returns the class name as it is used in the association definition. If :class_name
option is given in the association, the exact value of that option is returned here. If :class_name
option is not given, the name of the class is calculated from association name but is not resolved to the actual class.
The class name returned by this method may not correspond to a defined class, either because the corresponding class has not been loaded yet, or because the association references a non-existent class altogether. To obtain the association class, use #relation_class method.
# File 'lib/mongoid/association/relatable.rb', line 148
def relation_class_name @class_name ||= @options[:class_name] || ActiveSupport::Inflector.classify(name) end
#resolve_name(mod, name) (private)
This method can swallow exceptions produced during class loading, because it rescues NameError internally. Since this method attempts to load classes, failure during the loading process may also lead to there being incomplete class definitions.
Resolves the given class/module name in the context of the specified module, as Ruby would when a constant is referenced in the source.
# File 'lib/mongoid/association/relatable.rb', line 461
def resolve_name(mod, name) cls = exc = nil parts = name.to_s.split('::') if parts.first == '' parts.shift hierarchy = [Object] else hierarchy = namespace_hierarchy(mod) end hierarchy.each do |ns| begin parts.each do |part| # Simple const_get sometimes pulls names out of weird scopes, # perhaps confusing the receiver (ns in this case) with the # local scope. Walk the class hierarchy ourselves one node # at a time by specifying false as the second argument. ns = ns.const_get(part, false) end cls = ns break rescue NameError => e if exc.nil? exc = e end end end if cls.nil? # Raise the first exception, this is from the most specific namespace raise exc end cls end
#setter ⇒ String
The name of the setter on this object for assigning an associated object.
# File 'lib/mongoid/association/relatable.rb', line 201
def setter @setter ||= "#{name}=" end
#setup_index! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 345
def setup_index! @owner_class.index(index_spec, background: true) if indexed? end
#type_setter ⇒ String
Only relevant for polymorphic associations that take the :as
option.
Get the type setter.
# File 'lib/mongoid/association/relatable.rb', line 83
def type_setter @type_setter ||= "#{type}=" if type end
#validate! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 401
def validate! @options.keys.each do |opt| unless self.class::VALID_OPTIONS.include?(opt) raise Errors::InvalidRelationOption.new(@owner_class, name, opt, self.class::VALID_OPTIONS) end end [name, "#{name}?".to_sym, "#{name}=".to_sym].each do |n| if Mongoid.destructive_fields.include?(n) raise Errors::InvalidRelation.new(@owner_class, n) end end end