Cuando trabajamos con aplicaciones que manejan autenticación mediante JSON Web Token, uno de los pasos más importantes es vincular la información del usuario autenticado con los registros que este crea. Esto no solo mejora la trazabilidad de los datos, sino que también aporta seguridad al permitir que otros usuarios sepan exactamente quién generó cada registro antes de interactuar con él.
¿Por qué es importante asignar el usuario creador a cada registro?
En el contexto de una aplicación de rodadas para motociclistas, saber quién creó cada rodada es fundamental. Si el capitán del club publica una rodada, los miembros pueden confiar en la ruta y el punto de encuentro. Pero si un usuario desconocido crea una rodada en un lugar sospechoso a una hora inusual, los demás pueden decidir no asistir [0:30].
Este principio aplica a cualquier aplicación donde los usuarios generan contenido: siempre conviene asociar el creador al registro para dar contexto y confianza.
¿Cómo sobreescribir el método create en el controlador de Sails.js?
Sails.js ofrece el Blueprint API, que genera automáticamente los métodos CRUD sin necesidad de escribir código. Sin embargo, cuando necesitamos agregar lógica adicional, como inyectar el usuario autenticado, debemos definir manualmente el método que queremos personalizar [1:30].
¿Qué estructura tiene el método create personalizado?
El método debe llamarse exactamente create para que Sails sepa cuál de los métodos generados automáticamente debe reemplazar. Los demás métodos como update, delete o get siguen funcionando sin cambios [2:00].
javascript
async create(req, res) {
try {
const params = req.allParams();
const ride = await Ride.create({
title: params.title,
start: params.start,
end: params.end,
waypoints: params.waypoints,
user: req.user
}).fetch();
return res.ok(ride);
} catch (error) {
return res.serverError(error);
}
}
Es importante notar la diferencia entre params y req.user. Todos los atributos propios de la rodada se extraen de req.allParams(), mientras que el usuario se obtiene directamente de req.user [3:45].
¿De dónde viene req.user?
El objeto req.user se establece en el policy de autenticación. Este policy valida el token JWT y, al final del proceso, agrega el ID del usuario al objeto req antes de pasarlo al controlador [4:20]. Es decir, el flujo es:
- El policy verifica el token.
- Extrae la información del usuario.
- Asigna
req.user con el ID correspondiente.
- Llama a
next() para continuar hacia el controlador.
¿Cómo configurar la asociación en el modelo de Sails.js?
Al intentar guardar un campo user en el modelo Ride sin haberlo definido, Sails no lo reconocerá. Es necesario agregar una asociación en el modelo [5:15].
Dentro de Sails, los primitivos son atributos directos del objeto, como title, start, end y waypoints. Son propiedades que pertenecen exclusivamente a ese registro. En cambio, el usuario que crea la rodada puede crear múltiples rodadas, por lo que no es un atributo primitivo sino una asociación [5:40].
javascript
// api/models/Ride.js
module.exports = {
attributes: {
title: { type: 'string' },
start: { type: 'string' },
end: { type: 'string' },
waypoints: { type: 'json' },
user: { model: 'user' }
}
};
La clave está en usar model: 'user' en lugar de type. Sails interpreta esta configuración y automáticamente relaciona cada ride con el modelo User, resolviendo la referencia al consultar los datos [6:10].
¿Qué resultado obtenemos al consultar las rodadas?
Después de reiniciar el servidor con la opción Alter y crear una nueva rodada con el token de un usuario autenticado, al consultar todos los rides, Sails no solo devuelve el ID del usuario sino el objeto completo [7:00]. Esto significa que podemos mostrar el correo electrónico u otros datos del creador directamente en la interfaz.
- El ride incluye todos sus atributos primitivos.
- El campo
user contiene el objeto completo del usuario asociado.
- Se puede mostrar nombre, correo y cualquier dato disponible en el modelo User.
Un buen ejercicio para reforzar este conocimiento es agregar los campos name y lastName al modelo de usuario, de modo que al crear una rodada esa información quede disponible. Comparte cómo lo implementaste en los comentarios.