Contenido del curso

Listado de preguntas con Gravatar y Eloquent

Resumen

Diseñar un listado de preguntas en Laravel con Livewire requiere algo más que iterar registros: necesitas mostrar el avatar del autor, la categoría con su color, el conteo de respuestas y un enlace de acción. Aquí verás cómo cerrar ese diseño paso a paso conectando relaciones Eloquent, Gravatar y una consulta optimizada con withCount.

¿Cómo mostrar el avatar del usuario con Gravatar en Laravel?

El primer bloque del listado es la imagen del autor de la pregunta. La idea es traerla desde Gravatar, un servicio global que sirve avatares basados en el hash MD5 del email registrado.

Dentro de la vista Blade se imprime con la sintaxis {{ $pregunta->user->avatar() }} y se aplica una clase para esquinas redondeadas. Pero antes de que ese método funcione, hay dos piezas que conectar.

¿Por qué falla la relación user en el modelo Pregunta?

Al intentar acceder a $pregunta->user aparece un valor nulo porque la relación todavía no existe en el modelo. La tabla está vinculada físicamente, pero Eloquent no infiere la relación sola, hay que declararla [02:10].

En la entidad Pregunta (o Hilo) se agrega:

php public function user() { return $this->belongsTo(User::class); }

Una pregunta pertenece a un usuario, por eso usamos belongsTo. Ya con esto, el modelo sabe a dónde ir a buscar al autor.

¿Cómo se construye el método avatar() con Gravatar?

En User.php se define un método público que arma la URL con el email del usuario convertido a MD5:

php public function avatar() { return 'https://gravatar.com/avatar/' . md5($this->email) . '?s=50'; }

El parámetro s=50 define el tamaño en píxeles. Si el usuario tiene cuenta en Gravatar, aparece su foto real; si no, sale el avatar genérico, lo cual es esperable cuando trabajas con usuarios fake generados por seeders.

¿Qué es Gravatar y por qué se usa con MD5? Es un servicio que asocia avatares a emails. Para pedir la imagen, debes enviar el email convertido a hash MD5, así el servicio lo identifica sin exponer el correo en la URL.

¿Cómo conectar la categoría y su color a cada pregunta?

El siguiente bloque es la categoría. En la vista necesitas imprimir tanto el nombre como el color, y ambos viven en el modelo Categoria [04:30].

La relación se declara igual que con el usuario:

php public function category() { return $this->belongsTo(Category::class); }

Luego en Blade se usa {{ $pregunta->category->name }} para el texto y {{ $pregunta->category->color }} para aplicar el color dinámicamente. Con esto, cada tarjeta del listado refleja el color real de su categoría sin valores quemados.

¿Cómo contar respuestas con withCount en Livewire?

Mostrar cuántas respuestas tiene cada pregunta es donde más se nota la optimización. Lo ineficiente sería traer todas las respuestas y hacer count() en memoria. Lo correcto es delegarle el conteo a la base de datos.

Primero declaras la relación en Pregunta:

php public function respuestas() { return $this->hasMany(Respuesta::class); }

Después, en el componente Livewire ubicado en Http/Livewire, ajustas la consulta:

php Pregunta::withCount('respuestas')->get();

Este método genera automáticamente el campo respuestas_count en cada registro, listo para usar en la vista [07:15].

¿Qué hace withCount en Eloquent? Agrega una subconsulta que cuenta los registros relacionados y los devuelve en un campo nuevo, evitando cargar toda la colección. Es ideal para listados con contadores.

¿Cómo pluralizar respuesta o respuestas según el número?

Decir tres respuesta suena mal. La regla es simple: si el conteo es distinto de uno, agregas una s. Eso se resuelve con un operador ternario en Blade:

blade {{ $pregunta->respuestas_count }} respuesta{{ $pregunta->respuestas_count != 1 ? 's' : '' }}

Resultado: una respuesta, tres respuestas, dos respuestas. Pequeño detalle, gran diferencia en lectura.

¿Cómo agregar el icono de chat y el botón editar al listado?

Falta el remate visual. Junto al contador de respuestas se coloca un icono de chat sólido tomado de una librería como Heroicons. Pegas el SVG en la vista y le aplicas una clase de altura, por ejemplo h-4, para que escale bien con el texto.

Al lado se agrega un enlace de acción con la palabra editar y una clase que cambia el color a blanco al hacer hover. Para alinear icono, número y botón en una sola línea, el contenedor padre lleva las utilidades de Tailwind:

  • flex para activar el modelo de caja flexible.
  • items-center para centrar verticalmente icono y texto.
  • gap-1 para una brecha mínima entre elementos.

Con eso, la fila inferior de cada tarjeta queda ordenada: avatar, nombre del autor, fecha, categoría con color, icono de chat, conteo pluralizado y botón editar.

¿Qué piezas quedaron conectadas en el componente?

Repasando lo que hiciste fluir entre modelos y vista:

  1. Método avatar() en User que arma la URL de Gravatar con MD5.
  2. Relación belongsTo hacia User y Category en el modelo Pregunta.
  3. Relación hasMany hacia Respuesta para habilitar el conteo.
  4. Consulta con withCount('respuestas') en el componente Livewire.
  5. Operador ternario en Blade para pluralizar correctamente.

Esta es la base del listado. El botón editar todavía no tiene lógica, eso viene en la siguiente práctica. Ahora aplica esta configuración en tu proyecto y comparte abajo cómo te quedó tu vista.