¿Qué hace la gema active_model_serializers?
Esta gema básicamente nos ayuda a serializar los objetos, al igual que como hicimos en el capítulo anterior usando ActiveModel::Serializers
, pero con la diferencia que esta gema nos agrega una serie de funcionalidades que nos ayudan al manejo de estos objetos e incluso nos separan la lógica de serialización de nuestros controladores y modelos. Por lo general utilizamos esta gema para realizar APIs con formato JSON.
Demostración
Para la demostración de esta maravillosa gema veremos desde su instalación hasta la implementación, en algunos ejemplos sencillos, que podrás desarrollar fácilmente tu aplicación.
Instalación
Hasta este momento no hemos visto ni instalado ninguna gema en nuestra aplicación, ya es hora de hacerlo y como todo en Ruby on Rails te daras cuenta de lo fácil que resulta.
Básicamente la instalación de esta gema, en Ruby on Rails y en nuestra aplicación, sigue dos sencillos pasos. Primero agregamos en el archivo Gemlife nuestra gema de la siguiente manera:
gem "active_model_serializers"1 gem"active_model_serializers"
Luego, nos vamos a nuestra consola o terminal y nos dirigimos hasta el directorio donde está el proyecto. Entramos dentro de la carpeta del proyecto y ejecutamos la famosa línea de código para instalar las gemas:
bundle install1 bundle install
Una vez realizados estos dos sencillos pasos ya nuestra aplicación está lista para hacer uso de nuestra gema serializadora.
¿Cómo creamos el serializador?
Para crear el serializador sólo basta con ejecutar un línea de comando en nuestra consola o terminal. Si queremos crear un modelo desde cero y ya estamos seguros que vamos a necesitar serializar los objetos, porque queremos hacer un API o simplemente queremos mostrarlo en un formato de uso común (JSON), utilizamos el siguiente comando:
rails g resource nombre_modelo atributo1:string atributo2:string1 railsgresource nombre_modelo atributo1:stringatributo2:string
o
rails generate resource nombre_modelo atributo1:string atributo2:string1 rails generate resource nombre_modelo atributo1:stringatributo2:string
Como ven este comando nos crea los mismos archivos que cuando creamos un modelo, sólo que adicionalmente en la carpeta app nos agrega una nueva carpeta llamada serializers y a ésta un archivo Ruby donde desarrollamos la lógica para serializar.
También es posible crear un serializador a un objeto ya existente en nuestra aplicación de la siguiente manera:
rails g serializer nombre_modelo1 railsgserializer nombre_modelo
o
rails generate serializer nombre_modelo1 rails generate serializer nombre_modelo
Este comando sólo nos crea la clase en Ruby, donde desarrollamos la lógica para serializar el objeto que indicamos.
¿Cómo usar el serializador?
Una vez que creamos nuestro serializador nos damos cuenta que tenemos unos archivos Ruby nuevos dentro de la carpeta Serializer que se debió haber creado. Estos archivos deben tener algo como esto:
class UsuariosSerializer < ActiveModel::Serializer attributes :id, :nombre, :apellido, :nacimiento, :sexo end123 classUsuariosSerializer<ActiveModel::Serializer attributes:id,:nombre,:apellido,:nacimiento,:sexoend
Como ven es una simple clase que extiende de ActiveModel::Serializer
con los atributos del modelo que en nuestro caso es Usuario.
Probablemente cuando creamos el serializador con la segunda opción de este tutorial, debamos agregar los atributos del modelo a mano (Por defecto sólo se crea con el id)
Una vez revisada y modificada la clase serializadora del modelo simplemente nos vamos a nuestro controlador y creamos un método (Recuerda agregar la ruta al archivo routes.rb). Por ejemplo:
class Usuario < ApplicationController def serializador @ejemplo1 = Usuario.all render json: @ejemplo1 end end12345678 classUsuario<ApplicationController def serializador @ejemplo1 =Usuarioall render json:@ejemplo1 end end
Listo!, con este comando ya tenemos a todos los usuarios impresos en formato JSON en nuestra aplicación.
{ "nombreControlador": [ { "id": 6, "nombre": "Ramses", "apellido": "Velasquez", "nacimiento": "1968-05-09", "sexo": "m" }, { "id": 7, "nombre": "Perez", "apellido": "Juana", "nacimiento": "1996-05-09", "sexo": "f" } ] }123456789101112131415161718 { "nombreControlador":[ { "id":6, "nombre":"Ramses", "apellido":"Velasquez", "nacimiento":"1968-05-09", "sexo":"m" }, { "id":7, "nombre":"Perez", "apellido":"Juana", "nacimiento":"1996-05-09", "sexo":"f" } ]}
¿Cómo cambiar la estructura del JSON?
Probablemente necesitemos ocultar algunos atributos de nuestro modelo, cambiar el formato del algunos atributos e incluso agregar funciones que puedan cambiar la estructura de nuestro modelo original. El uso de funciones, el manejar la lógica de serialización completamente separada de nuestra aplicación y poder definir nuestros propios atributos, es lo que hace verdaderamente útil esta gema.
Imaginemos que necesitamos a los usuarios, pero en este caso particular sólo nos hace falta el nombre completo y la fecha de nacimiento de cada uno de los usuarios. Debemos desarrollar el serializador de la siguiente forma:
class UsuarioSerializer < ActiveModel::Serializer attributes :nacimiento, {full_name: :full_name} def full_name "#{object.nombre} #{object.apellido}" end end1234567 classUsuarioSerializer<ActiveModel::Serializer attributes:nacimiento,{full_name::full_name} def full_name "#{object.nombre} #{object.apellido}" endend
Como ven en el ejemplo, desarrollamos una función llamada full_name
donde concatenamos el nombre, ya que, para nuestro uso interno usamos el nombre por separado. Por último, para mostrar los atributos que queremos simplemente los sacamos o agregamos a nuestra lista de atributos.
Si deseáramos agregarle información extra a nuestra salida en formato JSON pudiéramos agregarlo directamente en nuestro controlador con la etiqueta meta
. Veamos el siguiente ejemplo y la salida que genera:
12345 def serializador @ejemplo1 =Usuarioall # meta_key es para cambiarle el nombre a la etiqueta que estamos agregando render json:@ejemplo1,meta:{total:10},meta_key:'meta_object' end
Para tener una salida parecida a la siguiente:
{ "nombre_controlador": [ { "nacimiento": "1988-05-09", "full_name": "Ricardo Sampayo" } ], "meta_object": { "total": 10 } }1234567891011 { "nombre_controlador":[ { "nacimiento":"1988-05-09", "full_name":"Ricardo Sampayo" } ], "meta_object":{ "total":10 }}
Por último, para terminar con este punto, esta gema también nos ofrece la posibilidad de tener varios serializadores con estructuras diferentes para ser usados según sea el caso. Por ejemplo, el serializador que hemos utilizado hasta ahora sólo tiene fecha de nacimiento y el nombre completo, pero, pudiéramos necesitar otro serializador que provea toda la información del modelo sin necesidad de aplicarle cambios al serializador principal. Veamos en el siguiente ejemplo cómo podemos llamar a un serializador diferente.
def serializador @ejemplo1 = Usuario.first render json: @ejemplo1 , serializer: UsuarioCustomSerializer end1234 def serializador @ejemplo1 =Usuariofirst render json:@ejemplo1,serializer:UsuarioCustomSerializer end
En caso de que el objeto que vayamos a serializar sea un arreglo de objetos utilizamos el siguiente:
def serializador @ejemplo1 = Usuario.all render json: @ejemplo1 , each_serializer: UsuarioCustomSerializer end1234 def serializador @ejemplo1 =Usuarioall render json:@ejemplo1,each_serializer:UsuarioCustomSerializer end
Conclusión
En esta lección hemos estudiado una nueva y muy útil gema para desarrollar en Ruby on Rails. Esta gema, aunque ofrece algunas funciones que ya nos ofrece el framework y estudiamos en el capítulo anterior ActiveModel, nos otorga más libertad al serializar nuestros objetos y aún más importante nos mantiene el código separado de la lógica de negocios manteniendo el código limpio, ordenado y eficiente.
Una vez más te recomiendo echarle un vistazo a la serie completa de Ruby desde cero, así como a las otras series de CodeHero, agradeciendo de antemano todas sus dudas y comentarios en la sección de comentarios.
¡Hasta el próximo capítulo!