Overview
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.
Asignar herencia
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.
Documentos incrustados
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
Comportamiento de la query
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".
Cambiar la clave del discriminador
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.
Cambiar el valor del discriminador
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.
Asociaciones integradas
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" } ] }
Contextos de Persistencia
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.
Información Adicional
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.