module Mongoid::Fields
This module defines behavior for fields.
Constants
- Boolean
Adds type-casting behavior to
Mongoid::Boolean
class.- IDS
Constant for all names of the _id field in a document.
This does not include aliases of _id field.
@api private
- INVALID_BSON_CLASSES
BSON classes that are not supported as field types
@api private
- StringifiedSymbol
- TRANSLATIONS_SFX
The suffix for generated translated fields.
@api private
- TYPE_MAPPINGS
For fields defined with symbols use the correct class.
Public Class Methods
Get the name of the provided field as it is stored in the database. Used in determining if the field is aliased or not. Recursively finds aliases for embedded documents and fields, delimited with period “.” character.
Note that this method returns the name of associations as they’re stored in the database, whereas the ‘relations` hash uses their in-code aliases. In order to check for membership in the relations hash, you would first have to look up the string returned from this method in the aliased_associations hash.
This method will not expand the alias of a belongs_to association that is not the last item. For example, if we had a School that has_many Students, and the field name passed was (from the Student’s perspective):
school._id
The alias for a belongs_to association is that association’s _id field. Therefore, expanding out this association would yield:
school_id._id
This is not the correct field name, because the intention here was not to get a property of the _id field. The intention was to get a property of the referenced document. Therefore, if a part of the name passed is a belongs_to association that is not the last part of the name, we won’t expand its alias, and return:
school._id
If the belongs_to association is the last part of the name, we will pass back the _id field.
@param [ String | Symbol ] name The name to get. @param [ Hash ] relations The associations. @param [ Hash ] aliased_fields The aliased fields. @param [ Hash ] aliased_associations The aliased associations.
@return [ String ] The name of the field as stored in the database.
@api private
# File lib/mongoid/fields.rb, line 415 def database_field_name(name, relations, aliased_fields, aliased_associations) return "" unless name.present? key = name.to_s segment, remaining = key.split('.', 2) # Don't get the alias for the field when a belongs_to association # is not the last item. Therefore, get the alias when one of the # following is true: # 1. This is the last item, i.e. there is no remaining. # 2. It is not an association. # 3. It is not a belongs association if !remaining || !relations.key?(segment) || !relations[segment].is_a?(Association::Referenced::BelongsTo) segment = aliased_fields[segment]&.dup || segment end return segment unless remaining relation = relations[aliased_associations[segment] || segment] if relation k = relation.klass "#{segment}.#{database_field_name(remaining, k.relations, k.aliased_fields, k.aliased_associations)}" else "#{segment}.#{remaining}" end end
Stores the provided block to be run when the option name specified is defined on a field.
No assumptions are made about what functionality the handler might perform, so it will always be called if the ‘option_name` key is provided in the field definition – even if it is false or nil.
@example
Mongoid::Fields.option :required do |model, field, value| model.validates_presence_of field if value end
@param [ Symbol ] option_name the option name to match against @param &block the handler to execute when the option is provided.
# File lib/mongoid/fields.rb, line 298 def option(option_name, &block) options[option_name] = block end
Return a map of custom option names to their handlers.
@example
Mongoid::Fields.options # => { :required => #<Proc:0x00000100976b38> }
@return [ Hash ] the option map
# File lib/mongoid/fields.rb, line 309 def options @options ||= {} end
Traverse down the association tree and search for the field for the given key. To do this, split the key by ‘.’ and for each part (meth) of the key:
-
If the meth is a field, yield the meth, field, and is_field as true.
-
If the meth is an association, update the klass to the association’s klass, and yield the meth, klass, and is_field as false.
The next iteration will use klass’s fields and associations to continue traversing the tree.
@param [ String ] key The key used to search the association tree. @param [ Hash ] fields The fields to begin the search with. @param [ Hash ] associations The associations to begin the search with. @param [ Hash ] aliased_associations The alaised associations to begin
the search with.
@param &block The block. @yieldparam [ Symbol ] The current method. @yieldparam [ Symbol | String ] The field or the relation. @yieldparam [ true | false ] Whether the second yield parameter is a
field or not.
@return [ Field ] The field found for the given key at the end of the
search. This will return nil if the last thing found is an association or no field was found for the given key.
@api private
# File lib/mongoid/fields.rb, line 340 def traverse_association_tree(key, fields, associations, aliased_associations) klass = nil field = nil key.split('.').each_with_index do |meth, i| fs = i == 0 ? fields : klass&.fields rs = i == 0 ? associations : klass&.relations as = i == 0 ? aliased_associations : klass&.aliased_associations # Associations can possibly have two "keys", their name and their alias. # The fields name is what is used to store it in the klass's relations # and field hashes, and the alias is what's used to store that field # in the database. The key inputted to this function is the aliased # key. We can convert them back to their names by looking in the # aliased_associations hash. aliased = meth if as && a = as.fetch(meth, nil) aliased = a.to_s end field = nil klass = nil if fs && f = fs[aliased] field = f yield(meth, f, true) if block_given? elsif rs && rel = rs[aliased] klass = rel.klass yield(meth, rel, false) if block_given? else yield(meth, nil, false) if block_given? end end field end
Public Instance Methods
Applies a single default value for the given name.
@example Apply a single default.
model.apply_default("name")
@param [ String ] name The name of the field.
# File lib/mongoid/fields.rb, line 183 def apply_default(name) unless attributes.key?(name) if field = fields[name] default = field.eval_default(self) unless default.nil? || field.lazy? attribute_will_change!(name) attributes[name] = default end end end end
Apply all the defaults at once.
@example Apply all the defaults.
model.apply_defaults
# File lib/mongoid/fields.rb, line 199 def apply_defaults pending_callbacks.delete(:apply_defaults) apply_pre_processed_defaults apply_post_processed_defaults end
Apply all default values to the document which are procs.
@example Apply all the proc defaults.
model.apply_post_processed_defaults
@return [ Array<String> ] The names of the proc defaults.
# File lib/mongoid/fields.rb, line 170 def apply_post_processed_defaults pending_callbacks.delete(:apply_post_processed_defaults) post_processed_defaults.each do |name| apply_default(name) end end
Apply all default values to the document which are not procs.
@example Apply all the non-proc defaults.
model.apply_pre_processed_defaults
@return [ Array<String> ] The names of the non-proc defaults.
# File lib/mongoid/fields.rb, line 158 def apply_pre_processed_defaults pre_processed_defaults.each do |name| apply_default(name) end end
Returns an array of names for the attributes available on this object.
Provides the field names in an ORM-agnostic way. Rails
v3.1+ uses this method to automatically wrap params in JSON requests.
@example Get the field names
document.attribute_names
@return [ Array<String> ] The field names
# File lib/mongoid/fields.rb, line 214 def attribute_names self.class.attribute_names end
Get the name of the provided field as it is stored in the database. Used in determining if the field is aliased or not.
@example Get the database field name.
model.database_field_name(:authorization)
@param [ String | Symbol ] name The name to get.
@return [ String ] The name of the field as it’s stored in the db.
# File lib/mongoid/fields.rb, line 227 def database_field_name(name) self.class.database_field_name(name) end
Does this field start with a dollar sign ($) or contain a dot/period (.)?
@api private
@param [ String ] name The field name.
@return [ true | false ] If this field is dotted or dollared.
# File lib/mongoid/fields.rb, line 263 def dot_dollar_field?(name) n = aliased_fields[name] || name fields.key?(n) && (n.include?('.') || n.start_with?('$')) end
Is the provided field a lazy evaluation?
@example If the field is lazy settable.
doc.lazy_settable?(field, nil)
@param [ Field ] field The field. @param [ Object
] value The current value.
@return [ true | false ] If we set the field lazily.
# File lib/mongoid/fields.rb, line 240 def lazy_settable?(field, value) !frozen? && value.nil? && field.lazy? end
Is the document using object ids?
@note Refactored from using delegate for class load performance.
@example Is the document using object ids?
model.using_object_ids?
@return [ true | false ] Using object ids.
# File lib/mongoid/fields.rb, line 252 def using_object_ids? self.class.using_object_ids? end
Validate whether or not the field starts with a dollar sign ($) or contains a dot/period (.).
@api private
@raise [ InvalidDotDollarAssignment ] If contains dots or starts with a dollar.
@param [ String ] name The field name.
# File lib/mongoid/fields.rb, line 276 def validate_writable_field_name!(name) if dot_dollar_field?(name) raise Errors::InvalidDotDollarAssignment.new(self.class, name) end end