Documents are the core objects in Mongoid and any object that is to be persisted to the database must include Mongoid::Document. The representation of a Document in MongoDB is a BSON object that is very similar to a Ruby hash or JSON object. Documents can be stored in their own collections in the database, or can be embedded in other Documents n levels deep.
Documents
Consider a simple class for modeling a person in an application. A person may have a first name, last name, and middle initial. We can define these attributes on a person by defining fields on our person object. Fields will default to type String in Mongoid.
person.rb:class Person
include Mongoid::Document
field :first_name
field :middle_initial
field :last_name
end
Fields other than strings must define a type in order to be properly typecasted when being set. Currently the valid types in Mongoid are: Array, BigDecimal, Boolean, Date, DateTime, Float, Integer, String, Symbol, Time and any object that inherits from Mongoid::Document. BigDecimals will get converted to and from Strings in the database.
person.rb:class Person
include Mongoid::Document
field :birthday, :type => Date
end
Fields may also have default values, set by adding a default option when defining the field. Note that default values MUST match the type of the field, and can accept lambdas.
person.rb:class Person
include Mongoid::Document
field :blood_alcohol_level, :type => Float, :default => 0.0
end
Documents are instantiated by calling new on the document and passing it a hash of attributes. If an attribute exists in the hash that is not defined as a field or is an association, then an exception will get raised. You can also pass a block.
person = Person.new(:first_name => "Ludwig", :last_name => "Beethoven")
person = Person.new do |p|
p.first_name = "Ludwig"
p.last_name = "Beethoven"
end
You can protect attributes from mass assignment by using attr_protected, or provide the inverse functionality with attr_accessible. This is for cases where sensitive fields cannot be accidentally set through a form submission or similar.
When using attr_protected all other fields will be able to be set via mass assignment.
class Person
include Mongoid::Document
field :first_name
attr_protected :_id
end
When using attr_accessible all other fields will not be able to be set via mass assignment.
class Person
include Mongoid::Document
field :first_name
field :last_name
attr_accessible :first_name, :last_name
end
By default Mongoid supports dynamic attributes - that is it will allow attributes to get set and persisted on the document even if a field was not defined for them. There is a slight 'gotcha' however when dealing with dynamic attributes in that Mongoid is not completely lenient about the use of method_missing and breaking the public interface of the Document class.
When dealing with dynamic attributes the following rules apply:
-
If the attribute exists in the document, Mongoid will provide you
with your standard getter and setter methods. For example, consider
a person who has an attribute of "gender" set on the document:
person[:gender] = "Male" person.gender # => returns "Male" person.gender = "Female" #=> will set gender to "Female" -
If the attribute does not already exist on the document, Mongoid
will not provide you with the getters and setters and will
enforce normal method_missing behavior. In this case you
must use the other provided accessor methods: ( [] and
[]= ) or ( read_attribute and
write_attribute ):
person[:gender] # => returns nil person[:gender] = "Male" # => set gender to "Male" person.read_attribute(:age) # => returns nil person.write_attribute(:age, 35) # => sets age to 35
If you define a field on your document that conflicts with a reserved method name in Mongoid, the configuration will raise an error. For a list of these you may look at Mongoid.destructive_fields.