Docs Menu
Docs Home
/ /

Herencia

En esta guía, aprenderá a implementar la herencia en sus modelos Mongoid. La herencia le permite aplicar las características de una clase principal a una o más clases secundarias.

Mongoid admite la herencia en documentos de nivel superior e incrustados. Cuando una clase de modelo secundaria hereda de una clase primaria, Mongoid copia los campos, asociaciones, validaciones y ámbitos de la clase primaria a la clase secundaria.

Al crear una clase de modelo secundaria, utilice el < Carácter para implementar la herencia de una clase padre especificada. Las siguientes clases modelo muestran cómo crear clases padre e hijas entre los modelos Person, Employee y Manager:

class Person
include Mongoid::Document
field :name, type: String
end
class Employee < Person
field :company, type: String
field :tenure, type: Integer
scope :new_hire, ->{ where(:tenure.lt => 1) }
end
class Manager < Employee
end

Mongoid guarda instancias de Person, Employee y Manager en la colección people. Mongoid establece el campo discriminador _type con el nombre de la clase del modelo en los documentos para garantizar que los documentos se devuelvan con los tipos esperados al realizar operaciones de lectura.

También se puede implementar un patrón de herencia en asociaciones incrustadas. De forma similar al comportamiento de las clases de modelo de nivel superior, Mongoid establece el campo discriminador _type en los documentos incrustados según la clase de modelo utilizada para crearlos.

El siguiente ejemplo añade una asociación incrustada al modelo Person y crea modelos padre e hijo para la clase anidada Info:

class Person
include Mongoid::Document
field :name, type: String
embeds_many :infos
end
...
class Info
include Mongoid::Document
field :active, type: Boolean
embedded_in :person
end
class Phone < Info
field :value, type: Float
field :country, type: String
end
class Email < Info
field :value, type: String
field :category, type: String
end

Al consultar una clase de modelo secundaria, la consulta solo devuelve documentos cuyo valor del campo _type coincida con la clase consultada o con otras clases secundarias. Por ejemplo, si consulta la clase Employee, la consulta devuelve documentos de la colección people cuyo valor _type sea "Employee" o "Manager". Todos los demás valores del discriminador se consideran instancias de la clase principal Person.

Al realizar una consulta sobre una clase padre como Person, Mongoid devuelve documentos que cumplen cualquiera de los siguientes criterios:

  • El valor del discriminador es el nombre de la clase principal o de cualquiera de las clases secundarias. Por ejemplo, "Person", "Employee" o "Manager".

  • Carece de valor discriminador.

  • El valor del discriminador no corresponde ni al padre ni a ninguna de sus clases hijas. Por ejemplo, "Director" o "Specialist".

Puede cambiar la clave discriminadora del nombre de campo predeterminado _type por cualquiera de los siguientes motivos:

  • Optimización: puede seleccionar una clave más corta, como _t.

  • Coherencia con un sistema existente: Es posible que esté utilizando un sistema o conjunto de datos existente que tiene claves predefinidas.

Puede cambiar la clave discriminadora a nivel de clase o global. Para cambiar la clave discriminadora a nivel de clase, puede establecer el nombre de la clave personalizada en la clase principal mediante el método discriminator_key.

El siguiente ejemplo demuestra cómo establecer una clave discriminadora personalizada al definir una clase de modelo:

class Person
include Mongoid::Document
field :name, type: String
self.discriminator_key = "sub_type"
end

Cuando crea una instancia de Person o cualquiera de sus clases secundarias, Mongoid agrega el campo sub_type a los documentos en MongoDB.

Nota

Puede cambiar la clave del discriminador solo en la clase principal. Mongoid genera un error si se establece una clave personalizada en cualquier clase secundaria.

Si cambia la clave del discriminador después de definir una clase secundaria, Mongoid agrega el nuevo campo de clave, pero el campo anterior permanece inalterado. Por ejemplo, suponga que agrega el siguiente código a su aplicación después de definir las clases del modelo:

Person.discriminator_key = "sub_type"

En este caso, cuando se crea una instancia de una clase secundaria como Employee, Mongoid agrega los campos sub_type y _type al documento.

También puede cambiar la clave discriminadora a nivel global, de modo que todas las clases utilicen la clave especificada en lugar del campo _type.

Puede establecer una clave global agregando el siguiente código a su aplicación antes de definir cualquier clase de modelo:

Mongoid.discriminator_key = "sub_type"

Todas las clases utilizan sub_type como clave discriminadora y no incluyen el campo _type.

Nota

Debe configurar la clave discriminadora a nivel global antes de definir las clases secundarias para que estas utilicen ese valor global. Si configura la clave global después de definir las clases secundarias, sus documentos guardados contendrán el campo predeterminado _type.

Puede personalizar el valor que Mongoid establece como discriminador en MongoDB. Utilice el método discriminator_value al definir una clase para personalizar el valor discriminador, como se muestra en el siguiente ejemplo:

class Employee
include Mongoid::Document
field :company, type: String
self.discriminator_value = "Worker"
end

Cuando se crea una instancia de Employee, el campo discriminador _type del documento tiene un valor de "Worker" en lugar del nombre de la clase.

Nota

Debido a que la personalización del valor del discriminador se declara en las clases secundarias, debe cargar las clases secundarias recuperadas por una consulta antes de enviar esa consulta.

En el ejemplo anterior, la definición de la clase Employee debe cargarse antes de consultar Person si los documentos devueltos incluyen instancias de Employee. La carga automática no puede resolver el valor del discriminador "Worker" para devolver documentos como instancias de Employee.

Puede crear cualquier tipo de clase padre o clase hija en una asociación incrustada mediante asignación o usando los métodos build y create. Puede pasar la clase de modelo deseada como segundo parámetro a los métodos build y create para indicar a Mongoid que cree esa instancia específica como un documento incrustado.

El siguiente código crea una instancia de Employee y luego demuestra cómo agregar documentos incrustados utilizando los diferentes métodos de creación:

# Creates a new Employee instance
e = Employee.create(
name: "Lance Huang",
company: "XYZ Communications",
tenure: 2
)
# Builds an Info object
e.infos.build({ active: true })
# Builds a Phone object
e.infos.build(
{ active: true, value: 1239007777, country: "USA" },
Phone
)
# Creates an Email object
e.infos.create(
{ active: true, value: "l.huang@company.com", category: "work" },
Email
)
# Creates and assigns an Email object
p = Email.new(active: false, value: "lanceh11@mymail.com", category: "personal" )
e.infos << p
# Saves the Employee instance to database
e.save

El siguiente documento está almacenado en la base de datos people:

{
"_id": {...},
"name": "Lance Huang",
"company": "XYZ Communications",
"tenure": 2,
"_type": "Employee",
"infos": [
{
"_id": {...},
"active": true,
"value": "l.huang@company.com",
"category": "work",
"_type": "Email"
},
{
"_id": {...},
"active": false,
"value": "lanceh11@mymail.com",
"category": "personal",
"_type": "Email"
},
{
"_id": {...},
"active": true,
"_type": "Info"
},
{
"_id": {...},
"active": true,
"value": 1239007777,
"country": "USA",
"_type": "Phone"
}
]
}

Puedes cambiar el contexto de persistencia de una clase secundaria desde el contexto de persistencia de su clase principal para almacenar el documento en una ubicación diferente a la predeterminada. Mediante el método store_in, puedes almacenar una instancia de una clase secundaria en una colección, base de datos o clúster diferente al de una instancia del modelo principal.

Las siguientes definiciones de modelo demuestran cómo utilizar el método store_in para almacenar instancias de Employee y Manager en una colección diferente a la colección people:

class Person
include Mongoid::Document
end
class Employee < Person
# Specifies "employees" as target collection
store_in collection: :employees
end
class Manager < Employee
# Specifies "managers" as target collection
store_in collection: :managers
end

Nota

Mongoid aún añade el campo discriminador a los documentos almacenados.

Si establece una colección de destino alternativa en algunas clases secundarias y no en otras, las instancias de las clases sin colecciones especificadas se almacenan en la colección asociada con la clase principal.

Nota

Cuando se cambia la colección de destino de una clase secundaria, las instancias de esa clase no aparecen en los resultados de las consultas en la clase principal.

Para obtener más información sobre cómo configurar la colección de destino para sus operaciones, consulte la Guíade configuración de persistencia.

Volver

Comportamientos de campo

En esta página