access

There are cases where you don't want Mongoid to allow attributes to be set through mass assignment, like passwords. This is a common event when submitting forms, and fields can be protected by using Mongoid's attr_protected or attr_accessible thanks to the wonders of Active Model.

protected

When defining a list of fields as protected, all other fields in the document will NOT be able to be set through mass assignment.

class User
  include Mongoid::Document
  field :first_name, type: String
  field :password, type: String
  attr_protected :password
end

# Set attributes on a person properly.
Person.new(first_name: "Corbin")
person.attributes = { first_name: "Corbin" }
person.write_attributes(first_name: "Corbin")

# Attempt to set attributes a person, raising an error.
Person.new(first_name: "Corbin", password: "password")
person.attributes = { first_name: "Corbin", password: "password" }
person.write_attributes(first_name: "Corbin", password: "password")

accessible

Providing a list of fields as accessible is simply the inverse of protecting them. Anything not defined as accessible will cause the error.

class User
  include Mongoid::Document
  field :first_name, type: String
  field :password, type: String
  attr_accessible :first_name
end

# Set attributes on a user properly.
User.new(first_name: "Corbin")
user.attributes = { first_name: "Corbin" }
user.write_attributes(first_name: "Corbin")

# Attempt to set attributes on a user, will silently ignore protected ones.
User.new(first_name: "Corbin", password: "password")
user.attributes = { first_name: "Corbin", password: "password" }
user.write_attributes(first_name: "Corbin", password: "password")

You can scope the mass assignment by role by providing the role as an option to the constructor or create methods.

class User
  include Mongoid::Document
  field :first_name, type: String
  field :password, type: String
  attr_accessible :first_name, as: [ :default, :admin ]
end

# Set attributes on a person for the admin role
Person.new({ first_name: "Corbin" }, as: :admin)
Person.create({ first_name: "Corbin" }, as: :default)
Person.create!({ first_name: "Corbin" }, as: :admin)

overriding

In the case you want to override the security in a single call, you can pass a block to the document constructor to set fields manually.

Person.new(first_name: "Corbin") do |person|
  person.password = "password"
end