Docs 菜单

自定义字段行为

在本指南中,您可以学习;了解如何自定义 Mongoid 模型中字段的行为。

您可以使用 default 选项将字段配置为默认值。 默认字段值可以是固定值或 Proc 值。

以下示例为 state字段指定固定的默认值:

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

以下示例为 fulfill_by字段指定 Proc默认值:

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

注意

加载类时,驾驶员会计算不是Proc 实例的默认值。实例化文档时,驾驶员会计算Proc 值。以下默认字段值不会产生等效结果:

# 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 }

您可以通过在 Proc实例中使用 self 关键字设立取决于文档状态的默认值。 以下示例将 fulfill_by默认值设置为取决于 submitted_at字段的状态:

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

默认下,Mongoid 在设置和初始化所有其他属性后应用 Proc默认值。 要在设置其他属性之前应用默认,请将 pre_processed 选项设立为 true,如以下示例所示:

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

提示

始终将 pre-processed 选项设立为 true,以便为 _id字段设立默认的Proc 值。

您可以指定一个单独的字段名称以存储在数据库中,同时在应用程序中仍按字段的原始名称引用该字段。 这可以节省存储空间,因为MongoDB将所有字段信息与每个文档一起存储。

您可以使用 as: 关键字设立备用存储名称。 以下示例创建了一个名为 name 的字段,Mongoid 将其存储在数据库中为 n

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

Mongoid 将 name字段存储为 "n",但您仍然可以在应用程序中作为 name访问权限该字段。

您可以使用 alias_attribute 选项为字段创建别名。 指定别名不会改变 Mongoid 在数据库中存储字段的方式,但它允许您在应用程序中通过不同名称访问权限字段。

以下示例为 name字段指定别名:

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

要删除字段别名,可以使用 unalias_attribute 选项。 以下示例删除 name字段的别名:

class Band
unalias_attribute :n
end

您还可以使用 unalias_attribute_id字段中删除预定义的 id 别名。 这可用于在 _id字段和 id字段中存储不同的值。

默认情况下,Mongoid 允许您重新定义模型上的字段。 要在重新定义字段时引发错误,请将 mongoid.yml文件中的 duplicate_fields_exception设立选项设置为 true

如果 duplicate_fields_exception 选项设立为 true,您仍然可以在定义字段时通过将 overwrite 选项设置为 true 来重新定义特定字段。 以下示例定义了 name字段,然后使用 overwrite 选项重新定义了该字段:

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

默认情况下,Mongoid 会定义文档上的 _id字段以包含 Mongoid 自动生成的 BSON::ObjectId 值。 您可以自定义类型,或通过在模型中指定 _id字段来指定其默认值。

以下示例创建了一个带有自定义 _id字段的 Band 类:

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

您可以省略 _id字段的默认值。 如果您没有为该字段指定默认值,Mongoid 将保留没有 _id 值的文档。 对于顶级文档, MongoDB 服务器会自动分配 _id 值。 但是,对于嵌入式文档,服务器不会分配 _id 值。

当您没有为 _id字段指定值时,Mongoid 不会从服务器检索自动分配的值。 因此,您无法使用 _id 值从数据库中检索文档。

如果某个值无法转换为指定的字段类型,则该值被视为不可转换。示例,在将数组分配给 Integer字段时,该大量被视为不可转换。

在 v8.0 及更高版本中,Mongoid 会将 nil 分配给不可转换的值。 原始的不可转换值与其字段名称一起存储在 attributes_before_type_cast 哈希中。

您可以指定与字段同名的方法并调用 read_attributewrite_attribute 方法对原始属性值进行操作,从而覆盖字段的默认getter 和 setter 方法。

以下示例为 Person 类的 name字段创建自定义 getter 和 setter:

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

您可以通过指定 attr_readonly 选项将字段指定为只读。 这允许您创建具有属性的文档,但不能更新它们。

以下示例创建一个 Band 类并将 name字段指定为只读:

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

如果调用批量更新方法(例如 update_attributes),并传入只读字段,则 Mongoid 会忽略该只读字段并更新所有其他字段。 如果您尝试显式更新只读字段,Mongoid 会引发 ReadonlyAttribute 异常。

注意

调用原子持久性操作符(例如 bitinc)仍会保留对只读字段的更改。

要学习;了解如何将整个模型指定为只读,请参阅执行数据操作指南的 只读文档部分。

Mongoid 通过使用 在 18gem 中 来支持本地化字段。当您本地化一个字段时,Mongoid 会将该字段存储为区域设置键和值的哈希值。 访问字段的行为与访问字符串值的行为相同。 您可以本地化任何字段类型的字段。

以下示例创建了一个带有本地化 review字段的 Product 类:

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!" }

您可以通过调用 _translations 方法一次性获取和设立所有翻译:

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

您可以通过启用 i18 n 回退功能来为本地化字段指定回退。

通过在您的环境中设置 config.i18n.fallbacks 配置设置并设置回退语言,在 Rails应用程序中启用回退:

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

通过将模块包含到 i18n后端并设置回退语言,在非 Rails 应用程序中启用回退:

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

启用回退后,如果活动语言没有翻译,则会在指定的回退语言中查找。

您可以在定义字段时将 fallbacks 选项设置为 false,以禁用指定字段的回退语言:

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

查询本地化字段时,Mongoid 会自动更改查询条件以匹配当前的区域设置。 以下示例查询 Product 类以获取 en区域设置的查看:

# 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!" }

注意

如果要对本地化字段进行广泛查询,我们建议为要查询的每个区域设置索引。