Docs Menu

Customize Field Behaviors

In this guide, you can learn how to customize the behavior of fields in Mongoid models.

You can configure fields to have default values by using the default option. Default field values can be either fixed or Proc values.

The following example specifies a fixed default value for the state field:

class Order
include Mongoid::Document
field :state, type: String, default: 'created'
end

The following example specifies a Proc default value for the fulfill_by field:

class Order
include Mongoid::Document
field :fulfill_by, type: Time, default: ->{ Time.now + 3.days }
end

Note

The driver evaluates default values that are not Proc instances when the class loads. The driver evaluates Proc values when the document is instantiated. The following default field values do not produce equivalent outcomes:

# Time.now is set to the time the class is loaded
field :submitted_at, type: Time, default: Time.now
# Time.now is set to the time the document is instantiated
field :submitted_at, type: Time, default: ->{ Time.now }

You can set a default value that depends on the document's state by using the self keyword in a Proc instance. The following example sets the fulfill_by default value to depend on the state of the submitted_at field:

field :fulfill_by, type: Time, default: ->{
self.submitted_at + 4.hours
}

By default, Mongoid applies Proc default values after setting and initializing all other attributes. To apply the default before setting the other attributes, set the pre_processed option to true, as shown in the following example:

field :fulfill_by, type: Time, default: ->{ Time.now + 3.days },
pre_processed: true

Tip

Always set the pre-processed option to true to set a default Proc value for the _id field.

You can specify a separate field name to store in the database, while still referring to the field by its original name in your application. This can save storage space, because MongoDB stores all field information along with every document.

You can set an alternate storage name by using the as: keyword. The following example creates a field called name that Mongoid stores in the database as n:

class Band
include Mongoid::Document
field :n, as: :name, type: String
end

Mongoid stores the name field as "n", but you can still access the field as name in your application.

You can create an alias for your field by using the alias_attribute option. Specifying an alias does not change how Mongoid stores the field in the database, but it allows you to access the field by a different name in your application.

The following example specifies an alias for the name field:

class Band
include Mongoid::Document
field :name, type: String
alias_attribute :n, :name
end

To remove a field alias, you can use the unalias_attribute option. The following example removes the alias for the name field:

class Band
unalias_attribute :n
end

You can also use unalias_attribute to remove the predefined id alias from the _id field. This can be used to store different values in the _id field and an id field.

By default, Mongoid allows you to redefine fields on a model. To raise an error when a field is redefined, set the duplicate_fields_exception configuration option in your mongoid.yml file to true.

If the duplicate_fields_exception option is set to true, you can still redefine a specific field by setting the overwrite option to true when you define the field. The following example defines the name field, and then redefines the field by using the overwrite option:

class Person
include Mongoid::Document
field :name
field :name, type: String, overwrite: true
end

By default, Mongoid defines the _id field on documents to contain a BSON::ObjectId value that Mongoid generates automatically. You can customize the type or specify the default value of the _id field by specifying it in your model.

The following example creates a Band class with a custom _id field:

class Band
include Mongoid::Document
field :name, type: String
field :_id, type: String, default: ->{ name }
end

You can omit the default value for the _id field. If you don't specify a default value for the field, Mongoid persists the document without an _id value. For top-level documents, the MongoDB server automatically assigns an _id value. However, for embedded documents, the server does not assign an _id value.

When you don't specify a value for the _id field, Mongoid does not retrieve the automatically assigned value from the server. Because of this, you cannot retrieve the document from the database by using the _id value.

A value is considered uncastable if it cannot be converted to the specified field type. For example, an array is considered uncastable when assigned to an Integer field.

In v8.0 and later, Mongoid assigns nil to values that are uncastable. The original uncastable value is stored in the attributes_before_type_cast hash with their field names.

You can override the default getter and setter methods for a field by specifying a method with the same name as the field and calling the read_attribute or write_attribute method to operate on the raw attribute value.

The following example creates a custom getter and setter for the name field of a Person class:

class Person
include Mongoid::Document
field :name, type: String
# Custom getter for 'name' to return the name in uppercase
def name
read_attribute(:name).upcase if read_attribute(:name)
end
# Custom setter for 'name' to store the name in lowercase
def name=(value)
write_attribute(:name, value.downcase)
end
end

You can specify a field to be read-only by specifying the attr_readonly option. This allows you to create documents with the attributes, but not update them.

The following example creates a Band class and specifies the name field as read-only:

class Band
include Mongoid::Document
field :name, type: String
field :origin, type: String
attr_readonly :name
end

If you call a mass-update method, such as update_attributes, and pass in a read-only field, Mongoid ignores the read-only field and updates all others. If you attempt to explicitly update a read-only field, Mongoid raises a ReadonlyAttribute exception.

Note

Calls to atomic persistence operators, such as bit and inc, still persist changes to the read-only field.

To learn about specifying entire models as read-only, see the Read-only Documents section of the Perform Data Operations guide.

Mongoid supports localized fields by using the i18n gem. When you localize a field, Mongoid stores the field as a hash of locale keys and values. Accessing the fields behaves in the same way as a string value. You can localize fields of any field type.

The following example creates a Product class with a localized review field:

class Product
include Mongoid::Document
field :review, type: String, localize: true
end
I18n.default_locale = :en
product = Product.new
product.review = "Marvelous!"
I18n.locale = :de
product.review = "Fantastisch!"
product.attributes
# Outputs: { "review" => { "en" => "Marvelous!", "de" => "Fantastisch!" }

You can get and set all translations at once by calling the _translations method:

product.review_translations
# Outputs: { "en" => "Marvelous!", "de" => "Fantastisch!" }
product.review_translations =
{ "en" => "Marvelous!", "de" => "Wunderbar!" }

You can specify fallbacks for localized fields by enabling the i18n fallbacks feature.

Enable fallbacks in a Rails application by setting the config.i18n.fallbacks configuration setting in your environment and setting the fallback languages:

config.i18n.fallbacks = true
config.after_initialize do
I18n.fallbacks[:de] = [ :en, :es ]
end

Enable fallbacks in non-Rails applications by including the module into the i18n backend and setting the fallback languages:

require "i18n/backend/fallbacks"
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
I18n.fallbacks[:de] = [ :en, :es ]

After enabling fallbacks, if an active language does not have have a translation, it is looked up in the specified fallback language.

You can disable fallback languages for a specified field by setting the fallbacks option to false when defining the field:

class Product
include Mongoid::Document
field :review, type: String, localize: true, fallbacks: false
end

When querying localized fields, Mongoid automatically alters the query criteria to match the current locale. The following example queries the Product class for a review in the en locale:

# Match all products with Marvelous as the review. The current locale is :en.
Product.where(review: "Marvelous!")
# The resulting MongoDB query filter: { "review.en" : "Marvelous!" }

Note

If you want to query extensively on localized fields, we recommend indexing each locale that you want to query on.