Overview
En esta guía, puedes aprender cómo implementar la herencia en tus modelos de Mongoid. La herencia 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 y documentos incrustados. Cuando una clase modelo hija hereda de una clase padre, Mongoid copia los campos, asociaciones, validaciones y ámbitos de la clase padre a la clase hija.
Asignar herencia
Al crear una clase de modelo secundario, use 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 al nombre de la clase del modelo en los documentos para garantizar que los documentos se devuelvan como los tipos esperados cuando se realicen 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
Cuando se realiza una query en una clase de modelo hijo, la query devuelve solo documentos en los que el valor del campo _type coincide con la clase consultada o con otras clases hijas. Por ejemplo, si realizas una query en la clase Employee, la query devolverá documentos de la colección people en los que el valor _type sea "Employee" o "Manager". Todos los demás valores de discriminador se consideran como instancias de la clase principal Person.
Al consultar en una clase principal como Person, Mongoid devuelve documentos que cumplen alguno 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".No tiene un valor de 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
Puedes cambiar la clave discriminatoria del nombre de campo por defecto _type por cualquiera de las siguientes razones:
Optimización: puedes 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.
Puedes cambiar la clave discriminatoria a nivel de clase o a nivel global. Para cambiar la clave discriminatoria a nivel de clase, puedes establecer el nombre de clave personalizado en la clase principal utilizando 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 cree una instancia de Person o de cualquiera de sus subclases, 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 cambias la clave de discriminador después de definir una clase hija, Mongoid agrega el nuevo campo clave, pero el campo anterior permanece sin cambios. Por ejemplo, supón que agregas el siguiente código a tu aplicación después de definir tus clases de modelos:
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 puedes cambiar la clave discriminadora a nivel global, para que todas las clases utilicen la clave especificada en lugar del campo _type.
Puedes establecer una clave global añadiendo el siguiente código a tu 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
Se debe establecer la clave discriminadora a nivel global antes de definir cualquier clase hija para que las clases utilicen ese valor global. Si estableces la clave global después de definir clases hijas, tus documentos guardados contienen el campo por defecto _type.
Cambiar el valor del discriminador
Puedes personalizar el valor que Mongoid establece como valor discriminador en MongoDB. Use el método discriminator_value al definir una clase para personalizar el valor del 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 clase Employee debe cargarse antes de realizar una query en Person si los documentos que se devuelven incluyen instancias de Employee. La carga automática no puede resolver el valor del discriminador "Worker" para devolver documentos como instancias de Employee.
Asociaciones incrustadas
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 se almacena 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 configuras una colección objetivo alternativa en algunas clases hijas y no en otras, las instancias de las clases sin colecciones especificadas se almacenan en la colección asociada con la clase madre.
Nota
Cuando cambie la colección de destino para una clase secundaria, las instancias de esa clase no aparecerán en los resultados de las consultas sobre 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.