Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

Operaciones CRUD

En esta guía, podrás aprender cómo utilizar Mongoid para realizar operaciones CRUD (crear, leer, actualizar, borrar) para modificar los datos en tus colecciones de MongoDB.

Mongoid admite operaciones CRUD que puedes realizar utilizando otros mapeadores de Ruby, como Active Record o Data Mapper. Cuando usas Mongoid, las operaciones generales de persistencia realizan actualizaciones atómicas solo en los campos que cambias en lugar de escribir todo el documento en la base de datos cada vez, como ocurre con otros ODM.

Puedes realizar operaciones de creación para añadir nuevos documentos a una colección. Si la colección no existe, la operación la crea implícitamente. Las siguientes secciones describen los métodos que puedes utilizar para crear nuevos documentos.

Usa el create! método en tu clase de modelo para insertar uno o más documentos en una colección. Si ocurre algún error de servidor o de validación, create! genera una excepción.

Para llamar a create!, pasa un hash de atributos que definan el documento que deseas insertar. Si deseas crear e insertar múltiples documentos, pasa un arreglo de hashes.

Este ejemplo muestra múltiples formas de llamar a create!. El primer ejemplo crea un único Person documento, y el segundo ejemplo crea dos Person documentos. El tercer ejemplo pasa un bloque do..end a create!. Mongoid invoca este bloque con los documentos pasados a create! como argumentos. El método create! intenta guardar el documento al final del bloque:

Person.create!(
first_name: "Heinrich",
last_name: "Heine"
)
Person.create!([
{ first_name: "Heinrich", last_name: "Heine" },
{ first_name: "Willy", last_name: "Brandt" }
])
Person.create!(first_name: "Heinrich") do |doc|
doc.last_name = "Heine"
end

Utiliza el método create para insertar un nuevo documento o varios nuevos documentos en una base de datos. create no lanza una excepción en errores de validación, a diferencia de la versión con sufijo !. create sí arroja excepciones en errores de servidor, como cuando se inserta un documento con un campo _id duplicado.

Si create encuentra algún error de validación, el documento no se inserta, sino que se devuelve junto con otros documentos insertados. Puede usar los métodos persisted?, new_record? o errors para verificar los documentos insertados en la base de datos.

Este ejemplo muestra cómo usar create para insertar nuevos documentos en MongoDB. El primer ejemplo muestra cómo insertar un documento Person. El segundo ejemplo intenta insertar dos Post documentos, pero el segundo documento no pasa la validación porque contiene un título duplicado. El ejemplo utiliza entonces el método persisted? para confirmar qué documentos se insertaron correctamente en la colección:

Person.create(
first_name: "Heinrich",
last_name: "Heine"
)
class Post
include Mongoid::Document
validates_uniqueness_of :title
end
posts = Post.create([{title: "test"}, {title: "test"}])
posts.map { |post| post.persisted? } # => [true, false]

Para obtener más información sobre los métodos persisted? y new_record?, consulte la SecciónAtributos de persistencia de esta guía.

Utiliza el método save! para guardar atómicamente los atributos modificados en la colección o para insertar un nuevo documento. save! genera una excepción si hay algún error de servidor o de validación. Puedes utilizar el método new para crear una nueva instancia de documento. Luego, utiliza save! para insertar el documento en la base de datos.

El siguiente ejemplo muestra cómo utilizar save! para insertar un nuevo documento Person y actualizar el campo first_name del documento existente:

person = Person.new(
first_name: "Esmeralda",
last_name: "Qemal"
)
person.save!
person.first_name = "Malik"
person.save!

El método save no genera una excepción si hay errores de validación. save sigue arrojando una excepción si hay errores del servidor. El método devuelve true si todos los atributos modificados se guardan, y false si se producen errores de validación.

Puedes pasar las siguientes opciones a save:

  • validate: falsePara omitir las validaciones al guardar el nuevo documento o los atributos actualizados.

  • touch: false: Para que no se actualice el campo updated_at al actualizar los atributos especificados. Esta opción no tiene efecto al insertar un nuevo documento.

El siguiente código utiliza save para insertar un nuevo documento. Luego, actualiza ese documento y aplica la opción validate: false.

person = Person.new(
first_name: "Tamara",
last_name: "Graham"
)
person.save
person.first_name = "Aubrey"
person.save(validate: false)

Puede realizar operaciones de lectura para recuperar documentos de una colección. Para obtener más información sobre cómo crear filtros de consulta para recuperar un subconjunto de sus documentos, consulte Especifica una query de documento guía.

Se puede usar el método attributes para recuperar los atributos de una instancia de modelo como un hash. Este hash también contiene los atributos de todos los documentos incrustados.

El siguiente ejemplo muestra cómo usar attributes:

person = Person.new(first_name: "James", last_name: "Nan")
person.save
puts person.attributes
{ "_id" => BSON::ObjectId('...'),
"first_name" => "James",
"last_name" => "Nan"
}

Puedes usar el método reload para acceder a la versión más reciente de un documento desde MongoDB. Cuando recargas un documento, Mongoid también recarga todas las asociaciones integradas en la misma query. Sin embargo, Mongoid no vuelve a cargar las asociaciones referenciadas. En su lugar, borra estos valores para que se carguen desde la base de datos durante el siguiente acceso.

Al llamar a reload en un documento, se pierden los cambios no guardados. El siguiente código muestra cómo llamar a reload en un documento:

band = Band.create!(name: 'Sun 1')
# => #<Band _id: ..., name: "Sun 1">
band.name = 'Moon 2'
# => #<Band _id: ..., name: "Moon 2">
band.reload
# => #<Band _id: ..., name: "Sun 1">

El ejemplo anterior actualiza el campo name en el documento band, pero no guarda el valor nuevo. Como Mongoid no persistió el cambio en el valor name, name contiene el valor original guardado en la base de datos.

Nota

Errores de documento no encontrado

Cuando Mongoid no puede encontrar un documento en la base de datos, por defecto genera un error Mongoid::Errors::DocumentNotFound. Se puede establecer la opción configuración raise_not_found_error en false en su archivo mongoid.yml para indicar a Mongoid que guarde un nuevo documento y establezca sus atributos a valores por defecto. En general, también cambia el valor del campo _id. Por este motivo, no recomendamos utilizar reload cuando raise_not_found_error está configurado en false.

Cuando llamas a reload en un documento que no se ha persistido, el método realiza una query find sobre el valor _id del documento.

El siguiente ejemplo llama a reload en un documento que no se ha guardado e imprime el valor del campo name. reload realiza una find operación utilizando el valor _id del documento, lo que genera que Mongoid recupere el documento existente en la colección:

existing = Band.create!(name: 'Photek')
band = Band.new(id: existing.id)
band.reload
puts band.name
Photek

Puedes realizar operaciones de actualización para modificar los documentos existentes de una colección. Si intentas actualizar un documento eliminado, Mongoid genera una excepción FrozenError.

Se puede utilizar el método update_attributes! para actualizar los atributos de una instancia de modelo existente. Este método genera una excepción si encuentra algún error de validación o del servidor.

El siguiente ejemplo muestra cómo utilizar update_attributes! para actualizar los atributos first_name y last_name de un documento existente:

person.update_attributes!(
first_name: "Maximilian",
last_name: "Hjalmar"
)

Tip

Mongoid ofrece la función de atributos anidados, que permite actualizar un documento y sus asociaciones anidadas en una sola llamada. Para obtener más información, consulte la guía «Usar atributos anidados».

El método update_attributes no genera una excepción en caso de errores de validación. El método devuelve true si pasa la validación y el documento se actualiza, y false en caso contrario.

El siguiente ejemplo muestra cómo usar update_attributes:

person.update_attributes(
first_name: "Hasan",
last_name: "Emine"
)

Puede usar el método update_attribute para omitir las validaciones y actualizar un atributo único de una instancia modelo.

El siguiente ejemplo muestra cómo usar update_attribute para actualizar el valor del atributo first_name de un documento:

person.update_attribute(:first_name, "Jean")

Puedes usar el método upsert para actualizar, insertar o reemplazar un documento.

upsert acepta una opción replace. Si configuras esta opción en true y el documento que invoca upsert ya existe en la base de datos, el nuevo documento reemplazará al que está en la base de datos. Se eliminan todos los campos en la base de datos que el nuevo documento no reemplace.

Si configura la opción replace en false y el documento existe en la base de datos, se actualiza. Mongoid no modifica ningún campo aparte de los especificados en el documento de actualización. Si el documento no existe en la base de datos, se inserta con los campos y valores especificados en el documento de actualización. La opción replace está configurada en false por defecto.

El siguiente ejemplo muestra cómo usar upsert para insertar primero un nuevo documento y luego reemplazarlo estableciendo replace: true:

person = Person.new(
first_name: "Balu",
last_name: "Rama"
)
person.upsert
person.first_name = "Ananda"
person.upsert(replace: true)

Puede usar el método touch para actualizar la marca de tiempo updated_at de un documento a la hora actual. touch propaga la actualización a cualquiera de las asociaciones belongs_to del documento. También puede pasar otro campo con valor de tiempo como una opción para actualizar también ese campo.

El siguiente ejemplo utiliza touch para actualizar las marcas de tiempo updated_at y audited_at:

person.touch(:audited_at)

Puedes realizar operaciones de borrado para remover documentos de una colección.

Puede usar el método delete para eliminar un documento de la base de datos. Al usar delete, Mongoid no ejecuta ninguna devolución de llamada. Si el documento no se guarda en la base de datos, delete intenta eliminar cualquier documento con el mismo valor _id.

El siguiente ejemplo muestra cómo usar el método delete y demuestra qué ocurre cuando se elimina un documento que no está guardado en la base de datos:

person = Person.create!(name: 'Edna Park')
unsaved_person = Person.new(id: person.id)
unsaved_person.delete
person.reload

En el ejemplo anterior, Mongoid produce un error Mongoid::Errors::DocumentNotFound cuando llamas a reload porque unsaved_person.delete elimina el documento person debido a que ambos documentos tienen el mismo valor para _id.

El método destroy funciona de forma similar a delete, excepto que Mongoid ejecuta devoluciones de llamada al llamar a destroy. Si el documento no se encuentra en la base de datos, destroy intenta eliminar cualquier documento con el mismo _id.

El siguiente ejemplo muestra cómo usar destroy:

person.destroy

El método delete_all elimina todos los documentos de la colección que estén modelados por tu clase modelo de Mongoid. delete_all no ejecuta callbacks.

El siguiente ejemplo muestra cómo usar delete_all para eliminar todos los Person documentos:

Person.delete_all

El método destroy_all elimina todos los documentos de la colección que estén modelados por tu clase modelo de Mongoid. Esta puede ser una operación costosa porque Mongoid carga todos los documentos en memoria.

El siguiente ejemplo muestra cómo usar destroy_all para eliminar todos los Person documentos:

Person.destroy_all

Las siguientes secciones describen los atributos que Mongoid proporciona y que puedes usar para verificar si un documento se incorpora a la base de datos.

El new_record? atributo devuelve true si la instancia del modelo aún no se ha guardado en la base de datos y en false caso contrario. Comprueba la condición opuesta persisted? a la del atributo.

El siguiente ejemplo muestra cómo usar new_record?:

person = Person.new(
first_name: "Tunde",
last_name: "Adebayo"
)
puts person.new_record?
person.save!
puts person.new_record?
true
false

El atributo persisted? devuelve true si Mongoid persiste la instancia del modelo y false en caso contrario. Verifica lo contrario que el atributo new_record?.

El siguiente ejemplo muestra cómo usar persisted?:

person = Person.new(
first_name: "Kiana",
last_name: "Kahananui"
)
puts person.persisted?
person.save!
puts person.persisted?
false
true

Mongoid ofrece varias maneras de acceder a los valores de campo de un documento. Las siguientes secciones describen cómo acceder a ellos.

Hay múltiples formas de obtener y establecer valores de campo en un documento. Si declaras explícitamente un campo, puedes obtener y establecer este valor de campo en el documento directamente. El siguiente ejemplo muestra cómo establecer y obtener el campo first_name de una instancia Person:

class Person
include Mongoid::Document
field :first_name
end
person = Person.new
person.first_name = "Artem"
person.first_name # => "Artem"

En el ejemplo anterior, primero se utiliza el atributo first_name para establecer un valor y luego se vuelve a llamar para recuperar el valor.

También puedes usar los métodos [] y [] = en una instancia del modelo Mongoid para acceder a los atributos usando la sintaxis hash. El método [] es un alias para el método read_attribute y el método [] = es un alias para el método write_attribute. El siguiente ejemplo muestra cómo obtener y establecer el campo alias first_name mediante los métodos [] y []=:

class Person
include Mongoid::Document
field :first_name, as: :fn
end
person = Person.new(first_name: "Artem")
person["fn"]
# => "Artem"
person[:first_name] = "Vanya"
# => "Artem"
person
# => #<Person _id: ..., first_name(fn): "Vanya">

Para obtener más información sobre estos métodos, consulta la siguientes sección de read_attribute y write_attribute de esta guía.

Puede utilizar los métodos read_attribute y write_attribute para especificar un comportamiento personalizado al leer o escribir campos. Puedes utilizar estos métodos al definir un modelo o llamándolos en instancias de modelo.

Para usar read_attribute para obtener un campo, pase su nombre al método. Para usar write_attribute para definir un campo, pase su nombre y el valor que se asignará.

El siguiente ejemplo utiliza read_attribute y write_attribute en una definición de modelo para definir first_name y first_name= como métodos que se utilizan para leer y guardar en el atributo fn:

class Person
include Mongoid::Document
def first_name
read_attribute(:fn)
end
def first_name=(value)
write_attribute(:fn, value)
end
end
person = Person.new
person.first_name = "Artem"
person.first_name
# => "Artem"

También puede llamar a read_attribute y write_attribute directamente en una instancia de modelo para obtener y establecer atributos. El siguiente ejemplo utiliza estos métodos en una instancia de modelo para obtener el atributo first_name y establecerlo en el valor "Pushkin".

class Person
include Mongoid::Document
field :first_name, as: :fn
end
person = Person.new(first_name: "Artem")
# => #<Person _id: ..., first_name(fn): "Artem">
person.read_attribute(:first_name)
# => "Artem"
person.read_attribute(:fn)
# => "Artem"
person.write_attribute(:first_name, "Pushkin")
person
# => #<Person _id: ..., first_name(fn): "Pushkin">

Puede escribir en varios campos al mismo tiempo utilizando los métodos attributes= o write_attributes en una instancia de modelo.

Para usar el método attributes=, invoque el método en una instancia del modelo y pase un objeto hash que contenga los campos y valores que desea configurar. El siguiente ejemplo muestra cómo usar el método attributes= para configurar los campos first_name y middle_name en un documento person:

person.attributes = { first_name: "Jean-Baptiste", middle_name: "Emmanuel" }

Para utilizar el método write_attributes, llama al método en una instancia de modelo e introduce los campos y valores que deseas fijar. El siguiente ejemplo muestra cómo usar el método write_attributes para configurar los campos first_name y middle_name en un documento person:

person.write_attributes(
first_name: "Jean-Baptiste",
middle_name: "Emmanuel",
)

Mongoid ofrece soporte para los siguientes operadores de actualización que puedes llamar como métodos en instancias de modelos. Estos métodos realizan operaciones de forma atómica y omiten validaciones y funciones de retorno.

La siguiente tabla describe los operadores compatibles con Mongoid:

Operador
Descripción
Ejemplo

add_to_set

Añade un valor especificado a un campo cuyo valor es un arreglo.

person.add_to_set(aliases: "Bond")

bit

Realiza una actualización bit a bit de un campo.

person.bit(age: { and: 10, or: 12 })

inc

Incrementa el valor de un campo.

person.inc(age: 1)

pop

Elimina el primer o el último elemento de un campo de matriz.

person.pop(aliases: 1)

pull

Elimina todas las instancias de un valor o valores que coinciden con una condición especificada de un campo de matriz.

person.pull(aliases: "Bond")

pull_all

Elimina todas las instancias de los valores especificados de un campo de arreglo.

person.pull_all(aliases: [ "Bond", "James" ])

push

Agrega un valor especificado a un campo de arreglo.

person.push(aliases: ["007","008"])

rename

Cambia el nombre de un campo en todos los documentos coincidentes.

person.rename(bday: :dob)

set

Updates an attribute on the model instance and, if the instance is already persisted, performs an atomic $set on the field, bypassing validations.
set can also deeply set values on Hash fields.
set can also deeply set values on embeds_one associations. If a model instance's embeds_one association document is nil, one is created before the update.
set cannot be used with has_one associations.
person = Person.create!(name: "Ricky Bobby")
# Updates `name` in the database
person.set(name: "Tyler Durden")

unset

Elimina un campo en particular de todos los documentos coincidentes.

person.unset(:name)

Para obtener más información sobre los operadores de actualización, consulte Operadores de actualización en el manual de MongoDB Server.

Para agrupar operaciones atómicas, puede usar el método atomically en una instancia de modelo. Mongoid envía todas las operaciones que pasa a un bloque atomically en un solo comando atómico.

Nota

Utilice transacciones para modificar múltiples documentos de forma atómica

Las operaciones atómicas se aplican a un solo documento a la vez. Por lo tanto, los atomically bloques anidados no pueden realizar cambios en varios documentos en una sola operación atómica. Para realizar cambios en varios documentos en una sola operación atómica, utilice una transacción multidocumento. Para obtener más información sobre las transacciones, consulte la guía Transacciones y sesiones.

El siguiente ejemplo muestra cómo usar atomically para actualizar de forma atómica múltiples campos en un documento:

person.atomically do
person.inc(age: 1)
person.set(name: 'Jake')
end

Puedes anidar bloques #atomically al actualizar un solo documento. Por defecto, Mongoid realiza escrituras atómicas definidas por cada bloque cuando el bloque finaliza. El siguiente ejemplo muestra cómo anidar atomically bloques:

person.atomically do
person.atomically do
person.inc(age: 1)
person.set(name: 'Jake')
end
raise 'An exception'
# Name and age changes are persisted
end

En el ejemplo anterior, las operaciones $inc y $set se ejecutan al final del bloque interno atomically.

El método atomically acepta una opción join_context: true para especificar que las operaciones se ejecutarán al final del bloque atomically más externo. Al habilitar esta opción, solo el bloque más externo, o el primer bloque donde join_context es false, guardará los cambios en la base de datos. El siguiente ejemplo configura la opción join_context en true:

person.atomically do
person.atomically(join_context: true) do
person.inc(age: 1)
person.set(name: 'Jake')
end
raise 'An exception'
# Name and age changes are not persisted
end

En el ejemplo anterior, Mongoid realiza las operaciones $inc y $set al final del bloque atomically más externo. Sin embargo, dado que se genera una excepción antes de que finalice el bloque y estas operaciones puedan ejecutarse, los cambios no se conservan.

También puedes habilitar la unión de contexto a nivel global, para que las operaciones se ejecuten en el bloque atomically más externo por defecto. Para habilitar esta opción a nivel global, define la opción de configuración join_contexts en true en tu archivo mongoid.yml. Para aprender más sobre las opciones de configuración de Mongoid, consulta Opciones de archivo de configuración autogestionadas.

Cuando se configura globalmente join_contexts a true, se puede utilizar la opción join_context: false en un bloque atomically para ejecutar operaciones al final de ese bloque solo para ese bloque.

Puedes rastrear los campos cambiados ("modificados") utilizando una API de Mongoid similar a la disponible en Active Model. Si modificas un campo definido en un modelo, Mongoid marca el modelo como modificado y te permite realizar acciones especiales. Las siguientes secciones describen cómo puedes interactuar con modelos modificados.

Mongoid registra los cambios desde el momento en que se instancia un modelo, ya sea como un nuevo documento o al recuperarlo de la base de datos, hasta que se guarda. Cualquier operación de persistencia borra los cambios.

Mongoid crea métodos específicos del modelo que te permiten explorar los cambios en una instancia del modelo. El siguiente código muestra maneras de ver los cambios en la instancia de tu modelo:

# Retrieves a person instance
person = Person.first
# Sets a new `name` value
person.name = "Sarah Frank"
# Checks to see if the document is changed
person.changed? # true
# Gets an array of changed fields.
person.changed # [ :name ]
# Gets a hash of the old and changed values for each field
person.changes # { "name" => [ "Sarah Frink", "Sarah Frank" ] }
# Checks if a specific field is changed
person.name_changed? # true
# Gets the changes for a specific field
person.name_change # [ "Sarah Frink", "Sarah Frank" ]
# Gets the previous value for a field
person.name_was # "Sarah Frink"

Nota

Seguimiento de cambios en las asociaciones

Configurar las asociaciones en un documento no modifica los hashes changes o changed_attributes. Esto es válido para todos los tipos de asociaciones. Sin embargo, cambiar el campo _id en las asociaciones referenciadas hace que los cambios se muestren en los hashes changes y changed_attributes.

Puedes restablecer un campo modificado a su valor anterior llamando al método reset, como se muestra en el siguiente código:

person = Person.first
person.name = "Sarah Frank"
# Reset the changed `name` field
person.reset_name!
person.name # "Sarah Frink"

Mongoid utiliza el seguimiento de cambios como base de todas las operaciones de persistencia. Evalúa los cambios en un documento y actualiza de forma atómica solo lo que ha cambiado, en comparación con otros marcos que sobreescriben todo el documento en cada guardado. Si no realiza ningún cambio, Mongoid no accede a la base de datos cuando llama a Model#save.

Después de persistir un modelo en MongoDB, Mongoid borra los cambios actuales. Sin embargo, todavía se puede ver qué cambios se hicieron previamente llamando al método previous_changes, como se muestra en el siguiente código:

person = Person.first
person.name = "Sarah Frank"
person.save # Clears out current changes
# Lists the previous changes
person.previous_changes
# { "name" => [ "Sarah Frink", "Sarah Frank" ] }

Mongoid tiene actualmente un problema que impide guardar en MongoDB los cambios en los atributos de tipos de contenedores, como Set o Array. Debe asignar todos los campos, incluidos los tipos de contenedores, para que sus valores se guarden en MongoDB.

Por ejemplo, agregar un elemento a una instancia Set como se muestra en el siguiente código no guarda los cambios en MongoDB:

person = Person.new
person.interests
# => #<Set: {}>
person.interests << 'Hiking'
# => #<Set: {"Hiking"}>
person.interests
# => #<Set: {}> # Change does not take effect

Para mantener este cambio, es necesario modificar el valor del campo fuera del modelo y asignarlo de nuevo al modelo, como se muestra en el siguiente código:

person = Person.new
interests = person.interests
# => #<Set: {}>
interests << 'Hiking'
# => #<Set: {"Hiking"}>
# Assigns the Set to the field
person.interests = interests
# => #<Set: {"Hiking"}>
person.interests
# => #<Set: {"Hiking"}>

Puede marcar documentos como de solo lectura de las siguientes maneras, según el valor del indicador de función Mongoid.legacy_readonly:

  • Si se desactiva este indicador, puedes marcar un documento como de solo lectura llamando al readonly! método en ese documento. El documento resultante, de solo lectura, genera un error de ReadonlyDocument si se intenta realizar cualquier operación de persistencia, incluyendo, pero no limitado a, guardar, actualizar, borrar y destruir. Note que recargar no restablece el estado de solo lectura.

    person = Person.first
    person.readonly? # => false
    person.readonly! # Sets the document as read-only
    person.readonly? # => true
    person.name = "Larissa Shay" # Changes the document
    person.save # => raises ReadonlyDocument error
    person.reload.readonly? # => true
  • Si esta indicador está activada on, puedes marcar un documento como de solo lectura después de aplicarle la proyección usando métodos como only o without. De esta forma, no es posible borrar ni destruir el documento de solo lectura porque Mongoid genera un error ReadonlyDocument, aunque sí es posible guardarlo y actualizarlo. El estado de solo lectura se restablece si se vuelve a cargar el documento.

    person = Person.only(:name).first
    person.readonly? # => true
    person.destroy # => raises ReadonlyDocument error
    person.reload.readonly? # => false

    Tip

    Proyección

    Para obtener más información sobre las proyecciones, consulte la sección Devolver campos especificados de la guía Modificar resultados de consulta.

También puedes hacer que un documento sea de solo lectura sobrescribiendo el método readonly?, como se muestra en el siguiente código:

class Person
include Mongoid::Document
field :name, type: String
def readonly?
true
end
end
person = Person.first
person.readonly? # => true
person.destroy # => raises ReadonlyDocument error

Para obtener más información sobre cómo especificar los filtros de query, revisa la guía Especificar una query de documento.

Para obtener más información sobre cómo configurar reglas de validación en sus modelos, consulte la guía Configurar validación de documentos.

Para obtener más información sobre cómo definir funciones de devolución de llamada, consulte la guía Personalizar funciones de devolución de llamada para modelos.

Volver

Agregación