module Mongoid::Fields::ClassMethods
Public Instance Methods
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
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
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
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
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
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 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 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
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 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
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 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 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 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 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 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 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 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
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
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
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 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
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
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
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