Customize Field Behaviors
On this page
Overview
In this guide, you can learn how to customize the behavior of fields in Mongoid models.
Specify Default Values
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.
Specify Storage Names
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.
Field Aliases
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.
Field Redefinition
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
Custom ID Field
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.
Uncastable Values
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.
Custom Getters and Setters
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
Read-Only Attributes
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.
Localize Fields
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.