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 =
# File 'lib/mongoid/association/relatable.rb', line 28
The primary key default.
'_id'.freeze
-
SHARED_OPTIONS =
# File 'lib/mongoid/association/relatable.rb', line 18
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.
-
#owner_class ⇒ Class
readonly
The class that owns 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 268
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 338
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 323
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 330
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 :
#owner_class ⇒ Class (readonly)
The class that owns this association.
# File 'lib/mongoid/association/relatable.rb', line 43
attr_reader :owner_class
#parent_inclusions ⇒ Array<String> (rw)
The associations above this one in the inclusion tree.
# File 'lib/mongoid/association/relatable.rb', line 316
def parent_inclusions @parent_inclusions ||= [] end
#parent_inclusions=(value) ⇒ Array<String> (rw)
The associations above this one in the inclusion tree.
# File 'lib/mongoid/association/relatable.rb', line 311
attr_writer :parent_inclusions
#validate? ⇒ true | false (readonly)
Whether the associated object(s) should be validated.
# File 'lib/mongoid/association/relatable.rb', line 300
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 67
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 98
def bindable?(doc); false; end
#class_name
Alias for #relation_class_name.
# File 'lib/mongoid/association/relatable.rb', line 156
alias :class_name :relation_class_name
#counter_cache_column_name ⇒ String
Get the counter cache column name.
# File 'lib/mongoid/association/relatable.rb', line 275
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 426
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 261
def create_relation(owner, target) relation.new(owner, target, self) end
#default_inverse (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 436
def default_inverse @default_inverse ||= klass.relations[inverse_klass.name.underscore] end
#define_autosaver! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 360
def define_autosaver! if autosave? Association::Referenced::AutoSave.define_autosave!(self) end end
#define_builder! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 366
def define_builder! Association::Builders.define_builder!(self) end
#define_counter_cache_callbacks! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 394
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 370
def define_creator! Association::Builders.define_creator!(self) end
#define_dependency! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 400
def define_dependency! if dependent Association::Depending.define_dependency!(self) end end
#define_existence_check! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 382
def define_existence_check! Association::Accessors.define_existence_check!(self) end
#define_getter! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 374
def define_getter! Association::Accessors.define_getter!(self) end
#define_ids_getter! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 386
def define_ids_getter! Association::Accessors.define_ids_getter!(self) end
#define_ids_setter! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 390
def define_ids_setter! Association::Accessors.define_ids_setter!(self) end
#define_setter! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 378
def define_setter! Association::Accessors.define_setter!(self) end
#define_touchable! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 354
def define_touchable! if touchable? Touchable.define_touchable!(self) end end
#extension ⇒ Module
Get the extension.
# File 'lib/mongoid/association/relatable.rb', line 284
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 250
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 220
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 80
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 51
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 291
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 123
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 346
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 190
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 183
def inverse_class_name @inverse_class_name ||= @owner_class.name end
#inverse_klass
Alias for #inverse_class.
# File 'lib/mongoid/association/relatable.rb', line 193
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 130
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 240
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 106
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 199
def key stores_foreign_key? ? foreign_key : primary_key end
#klass
Alias for #relation_class.
# File 'lib/mongoid/association/relatable.rb', line 178
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 229
def path(document) relation.path(document) end
#polymorph! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 420
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 172
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 153
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 466
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 206
def setter @setter ||= "#{name}=" end
#setup_index! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 350
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 88
def type_setter @type_setter ||= "#{type}=" if type end
#validate! (private)
[ GitHub ]# File 'lib/mongoid/association/relatable.rb', line 406
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