module Mongoid::Fields::ClassMethods

Public Instance Methods

attribute_names() click to toggle source

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

Model.attribute_names

@return [ Array<String> ] The field names

# File lib/mongoid/fields.rb, line 454
def attribute_names
  fields.keys
end
cleanse_localized_field_names(name) click to toggle source

Removes the _translations from the given field name. This is done only when there doesn’t already exist a field name or relation with the same name (i.e. with the _translations suffix). This check for an existing field is done recursively

@param [ String | Symbol ] name The name of the field to cleanse.

@return [ Field ] The field name without _translations

# File lib/mongoid/fields.rb, line 100
def cleanse_localized_field_names(name)
  name = database_field_name(name.to_s)

  klass = self
  [].tap do |res|
    ar = name.split('.')
    ar.each_with_index do |fn, i|
      key = fn
      unless klass.fields.key?(fn) || klass.relations.key?(fn)
        if fn.end_with?(TRANSLATIONS_SFX)
          key = fn.delete_suffix(TRANSLATIONS_SFX)
        else
          key = fn
        end

      end
      res.push(key)

      if klass.fields.key?(fn)
        res.push(ar.drop(i+1).join('.')) unless i == ar.length - 1
        break
      elsif klass.relations.key?(fn)
        klass = klass.relations[key].klass
      end
    end
  end.join('.')
end
database_field_name(name) click to toggle source

Get the name of the provided field as it is stored in the database. Used in determining if the field is aliased or not.

@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 464
def database_field_name(name)
  Fields.database_field_name(name, relations, aliased_fields, aliased_associations)
end
extract_id_field(attributes) click to toggle source

Extracts the id field from the specified attributes hash based on aliases defined in this class.

@param [ Hash ] attributes The attributes to inspect.

@return [ Object ] The id value.

@api private

# File lib/mongoid/fields.rb, line 83
def extract_id_field(attributes)
  id_fields.each do |k|
    if v = attributes[k]
      return v
    end
  end
  nil
end
field(name, options = {}) click to toggle source

Defines all the fields that are accessible on the Document For each field that is defined, a getter and setter will be added as an instance method to the Document.

@example Define a field.

field :score, type: Integer, default: 0

@param [ Symbol ] name The name of the field. @param [ Hash ] options The options to pass to the field.

@option options [ Class | Symbol | String ] :type The type of the field. @option options [ String ] :label The label for the field. @option options [ Object | Proc ] :default The field’s default.

@return [ Field ] The generated field

# File lib/mongoid/fields.rb, line 483
def field(name, options = {})
  named = name.to_s
  Validators::Macro.validate(self, name, options)
  added = add_field(named, options)
  descendants.each do |subclass|
    subclass.add_field(named, options)
  end
  added
end
id_fields() click to toggle source

Returns the list of id fields for this model class, as both strings and symbols.

@return [ Array<Symbol | String> ] List of id fields.

@api private

# File lib/mongoid/fields.rb, line 64
def id_fields
  IDS.dup.tap do |id_fields|
    aliased_fields.each do |k, v|
      if v == '_id'
        id_fields << k.to_sym
        id_fields << k
      end
    end
  end
end
replace_field(name, type) click to toggle source

Replace a field with a new type.

@example Replace the field.

Model.replace_field("_id", String)

@param [ String ] name The name of the field. @param [ Class ] type The new type of field.

@return [ Serializable ] The new field.

# File lib/mongoid/fields.rb, line 502
def replace_field(name, type)
  remove_defaults(name)
  add_field(name, fields[name].options.merge(type: type))
end
traverse_association_tree(key, &block) click to toggle source

Traverse down the association tree and search for the field for the given key.

@param [ String ] key The key used to search the association tree. @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 533
def traverse_association_tree(key, &block)
  Fields.traverse_association_tree(key, fields, relations, aliased_associations, &block)
end
using_object_ids?() click to toggle source

Convenience method for determining if we are using BSON::ObjectIds as our id.

@example Does this class use object ids?

person.using_object_ids?

@return [ true | false ] If the class uses BSON::ObjectIds for the id.

# File lib/mongoid/fields.rb, line 514
def using_object_ids?
  fields["_id"].object_id_field?
end

Protected Instance Methods

add_defaults(field) click to toggle source

Add the defaults to the model. This breaks them up between ones that are procs and ones that are not.

@example Add to the defaults.

Model.add_defaults(field)

@param [ Field ] field The field to add for.

@api private

# File lib/mongoid/fields.rb, line 548
def add_defaults(field)
  default, name = field.default_val, field.name.to_s
  remove_defaults(name)
  unless default.nil?
    if field.pre_processed?
      pre_processed_defaults.push(name)
    else
      post_processed_defaults.push(name)
    end
  end
end
add_field(name, options = {}) click to toggle source

Define a field attribute for the Document.

@example Set the field.

Person.add_field(:name, :default => "Test")

@param [ Symbol ] name The name of the field. @param [ Hash ] options The hash of options.

@api private

# File lib/mongoid/fields.rb, line 569
def add_field(name, options = {})
  aliased = options[:as]
  aliased_fields[aliased.to_s] = name if aliased
  field = field_for(name, options)
  fields[name] = field
  add_defaults(field)
  create_accessors(name, name, options)
  create_accessors(name, aliased, options) if aliased
  process_options(field)
  create_dirty_methods(name, name)
  create_dirty_methods(name, aliased) if aliased
  field
end
create_accessors(name, meth, options = {}) click to toggle source

Create the field accessors.

@example Generate the accessors.

Person.create_accessors(:name, "name")
person.name #=> returns the field
person.name = "" #=> sets the field
person.name? #=> Is the field present?
person.name_before_type_cast #=> returns the field before type cast

@param [ Symbol ] name The name of the field. @param [ Symbol ] meth The name of the accessor. @param [ Hash ] options The options.

@api private

# File lib/mongoid/fields.rb, line 622
def create_accessors(name, meth, options = {})
  field = fields[name]

  create_field_getter(name, meth, field)
  create_field_getter_before_type_cast(name, meth)
  create_field_setter(name, meth, field)
  create_field_check(name, meth)

  if options[:localize]
    create_translations_getter(name, meth)
    create_translations_setter(name, meth, field)
    localized_fields[name] = field
  end
end
create_field_check(name, meth) click to toggle source

Create the check method for the provided field.

@example Create the check.

Model.create_field_check("name", "name")

@param [ String ] name The name of the attribute. @param [ String ] meth The name of the method.

@api private

# File lib/mongoid/fields.rb, line 714
def create_field_check(name, meth)
  generated_methods.module_eval do
    re_define_method("#{meth}?") do
      value = read_raw_attribute(name)
      lookup_attribute_presence(name, value)
    end
  end
end
create_field_getter(name, meth, field) click to toggle source

Create the getter method for the provided field.

@example Create the getter.

Model.create_field_getter("name", "name", field)

@param [ String ] name The name of the attribute. @param [ String ] meth The name of the method. @param [ Field ] field The field.

@api private

# File lib/mongoid/fields.rb, line 647
def create_field_getter(name, meth, field)
  generated_methods.module_eval do
    re_define_method(meth) do
      raw = read_raw_attribute(name)
      if lazy_settable?(field, raw)
        write_attribute(name, field.eval_default(self))
      else
        process_raw_attribute(name.to_s, raw, field)
      end
    end
  end
end
create_field_getter_before_type_cast(name, meth) click to toggle source

Create the getter_before_type_cast method for the provided field. If the attribute has been assigned, return the attribute before it was type cast. Otherwise, delegate to the getter.

@example Create the getter_before_type_cast.

Model.create_field_getter_before_type_cast("name", "name")

@param [ String ] name The name of the attribute. @param [ String ] meth The name of the method.

@api private

# File lib/mongoid/fields.rb, line 671
def create_field_getter_before_type_cast(name, meth)
  generated_methods.module_eval do
    re_define_method("#{meth}_before_type_cast") do
      if has_attribute_before_type_cast?(name)
        read_attribute_before_type_cast(name)
      else
        send meth
      end
    end
  end
end
create_field_setter(name, meth, field) click to toggle source

Create the setter method for the provided field.

@example Create the setter.

Model.create_field_setter("name", "name")

@param [ String ] name The name of the attribute. @param [ String ] meth The name of the method. @param [ Field ] field The field.

@api private

# File lib/mongoid/fields.rb, line 693
def create_field_setter(name, meth, field)
  generated_methods.module_eval do
    re_define_method("#{meth}=") do |value|
      val = write_attribute(name, value)
      if field.foreign_key?
        remove_ivar(field.association.name)
      end
      val
    end
  end
end
create_translations_getter(name, meth) click to toggle source

Create the translation getter method for the provided field.

@example Create the translation getter.

Model.create_translations_getter("name", "name")

@param [ String ] name The name of the attribute. @param [ String ] meth The name of the method.

@api private

# File lib/mongoid/fields.rb, line 732
def create_translations_getter(name, meth)
  generated_methods.module_eval do
    re_define_method("#{meth}#{TRANSLATIONS_SFX}") do
      attributes[name] ||= {}
      attributes[name].with_indifferent_access
    end
    alias_method :"#{meth}_t", :"#{meth}#{TRANSLATIONS_SFX}"
  end
end
create_translations_setter(name, meth, field) click to toggle source

Create the translation setter method for the provided field.

@example Create the translation setter.

Model.create_translations_setter("name", "name")

@param [ String ] name The name of the attribute. @param [ String ] meth The name of the method. @param [ Field ] field The field.

@api private

# File lib/mongoid/fields.rb, line 752
def create_translations_setter(name, meth, field)
  generated_methods.module_eval do
    re_define_method("#{meth}#{TRANSLATIONS_SFX}=") do |value|
      attribute_will_change!(name)
      value&.transform_values! do |_value|
        field.type.mongoize(_value)
      end
      attributes[name] = value
    end
    alias_method :"#{meth}_t=", :"#{meth}#{TRANSLATIONS_SFX}="
  end
end
field_for(name, options) click to toggle source

Create a field for the given name and options.

@param [ Symbol ] name The name of the field. @param [ Hash ] options The hash of options.

@return [ Field ] The created field.

@api private

# File lib/mongoid/fields.rb, line 802
def field_for(name, options)
  opts = options.merge(klass: self)
  opts[:type] = retrieve_and_validate_type(name, options[:type])
  return Fields::Localized.new(name, opts) if options[:localize]
  return Fields::ForeignKey.new(name, opts) if options[:identity]
  return Fields::Encrypted.new(name, opts) if options[:encrypt]
  Fields::Standard.new(name, opts)
end
generated_methods() click to toggle source

Include the field methods as a module, so they can be overridden.

@example Include the fields.

Person.generated_methods

@return [ Module ] The module of generated methods.

@api private

# File lib/mongoid/fields.rb, line 773
def generated_methods
  @generated_methods ||= begin
    mod = Module.new
    include(mod)
    mod
  end
end
process_options(field) click to toggle source

Run through all custom options stored in Mongoid::Fields.options and execute the handler if the option is provided.

@example

Mongoid::Fields.option :custom do
  puts "called"
end

field = Mongoid::Fields.new(:test, :custom => true)
Person.process_options(field)
# => "called"

@param [ Field ] field the field to process

@api private

# File lib/mongoid/fields.rb, line 598
def process_options(field)
  field_options = field.options

  Fields.options.each_pair do |option_name, handler|
    if field_options.key?(option_name)
      handler.call(self, field, field_options[option_name])
    end
  end
end
remove_defaults(name) click to toggle source

Remove the default keys for the provided name.

@example Remove the default keys.

Model.remove_defaults(name)

@param [ String ] name The field name.

@api private

# File lib/mongoid/fields.rb, line 789
def remove_defaults(name)
  pre_processed_defaults.delete_one(name)
  post_processed_defaults.delete_one(name)
end
retrieve_and_validate_type(name, type) click to toggle source

Get the class for the given type.

@param [ Symbol ] name The name of the field. @param [ Symbol | Class ] type The type of the field.

@return [ Class ] The type of the field.

@raise [ Mongoid::Errors::InvalidFieldType ] if given an invalid field

type.

@api private

# File lib/mongoid/fields.rb, line 822
def retrieve_and_validate_type(name, type)
  result = TYPE_MAPPINGS[type] || unmapped_type(type)
  raise Errors::InvalidFieldType.new(self, name, type) if !result.is_a?(Class)

  if unsupported_type?(result)
    warn_message = "Using #{result} as the field type is not supported. "
    if result == BSON::Decimal128
      warn_message += 'In BSON <= 4, the BSON::Decimal128 type will work as expected for both storing and querying, but will return a BigDecimal on query in BSON 5+. To use literal BSON::Decimal128 fields with BSON 5, set Mongoid.allow_bson5_decimal128 to true.'
    else
      warn_message += 'Saving values of this type to the database will work as expected, however, querying them will return a value of the native Ruby Integer type.'
    end
    Mongoid.logger.warn(warn_message)
  end

  result
end
unmapped_type(type) click to toggle source

Returns the type of the field if the type was not in the TYPE_MAPPINGS hash.

@param [ Symbol | Class ] type The type of the field.

@return [ Class ] The type of the field.

@api private

# File lib/mongoid/fields.rb, line 847
def unmapped_type(type)
  if "Boolean" == type.to_s
    Mongoid::Boolean
  else
    type || Object
  end
end
unsupported_type?(type) click to toggle source

Queries whether or not the given type is permitted as a declared field type.

@param [ Class ] type The type to query

@return [ true | false ] whether or not the type is supported

@api private

# File lib/mongoid/fields.rb, line 863
def unsupported_type?(type)
  return !Mongoid::Config.allow_bson5_decimal128? if type == BSON::Decimal128
  INVALID_BSON_CLASSES.include?(type)
end