martes, 30 de junio de 2026

Migraciones en Laravel

Quiero en una migración, cambiar el nombre de una tabla.

En una migración de Laravel puedes cambiar el nombre de una tabla usando el método:

Schema::rename('nombre_actual', 'nuevo_nombre');

Ejemplo completo de migración

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::rename('pacientes', 'patients');
}

public function down(): void
{
Schema::rename('patients', 'pacientes');
}
};

Cosas a tener en cuenta

  • Esto solo cambia el nombre de la tabla, no toca columnas ni datos.
  • Laravel no hace magia con relaciones: si tienes foreign keys, asegúrate de que sigan funcionando (en la mayoría de casos no se rompen, pero depende del motor y constraints).
  • Siempre define el down() para poder revertir con php artisan migrate:rollback.

Si usas SQLite o casos raros

Algunas bases pueden requerir cuidado extra con constraints, pero en MySQL/PostgreSQL normalmente funciona directo.


Si quieres, puedo ayudarte a hacer un “rename seguro” cuando hay foreign keys involucradas (ahí ya hay un par de trampas típicas). 


¿Hay workflows predefinidos para trabajar con versionado de código, migraciones y seeds?

Sí. En Laravel y en desarrollo web en general hay workflows bastante establecidos que combinan versionado (Git), migraciones y seeds/seeders para mantener consistencia entre entornos.


🧭 Workflow típico recomendado

1. Versionado (Git como base)

  • Todo cambio de esquema va en una rama (feature/...)

  • Cada cambio de DB = commit junto con su migración

  • Nunca se edita una migración ya ejecutada en producción (se crea otra nueva)


2. Migraciones (estructura de la base)

Flujo estándar:

  1. Crear migración

    php artisan make:migration create_pacientes_table
    
  2. Definir cambios en up() / down()

  3. Ejecutar localmente:

    php artisan migrate
    
  4. Commit junto con el código que depende de esa tabla

👉 Regla clave: la base de datos también “viaja en Git” a través de migraciones


3. Seeders (datos iniciales o de prueba)

Workflow típico:

  • Crear seeder:

    php artisan make:seeder PacienteSeeder
    
  • Ejecutar:

    php artisan db:seed
    

O en conjunto con migraciones:

php artisan migrate --seed

4. Refresh completo (entornos de desarrollo)

Muy usado para resetear todo:

php artisan migrate:fresh --seed

👉 Borra todo y reconstruye DB desde cero.


5. Workflow combinado (el “ideal”)

Cuando haces una feature:

  1. Crear migración nueva

  2. Crear/actualizar modelos + lógica

  3. Crear o actualizar seeder si aplica

  4. Commit:

    • migración

    • seeders

    • código

  5. En otro entorno:

    git pull
    php artisan migrate
    php artisan db:seed
    

🧠 Buenas prácticas clave

  • Nunca modifiques migraciones ya compartidas (crea nuevas)

  • Seeders no son para producción crítica (salvo defaults)

  • Usa factories + seeders para datos fake

  • Mantén migraciones idempotentes y reversibles

  • Una migración = una intención clara


Si quieres, puedo proponerte un workflow “pro” tipo equipo (con staging, producción, rollback seguro y versionado de schema más estricto).


En teoría, si hago uno por uno el checkout de cada commit, ejecuto las migraciones según un workflow preestablecido, y ejecuto los seeders según un workflow preestablecido, no tendría que aparecer ningún error, y la app tendría que poder levantar con sus datos acordes a cada commit que checkoutee. ¿Qué hay de cierto en esta afirmación?

Tu afirmación es correcta en teoría, pero no es garantizable en la práctica sin condiciones muy estrictas.


✅ Qué es cierto

Si cumples estas condiciones:

  • migraciones siempre backward-compatible

  • seeders deterministas (no dependen de estado externo cambiante)

  • orden de ejecución consistente (migrate en orden histórico)

  • el código de cada commit es coherente con su schema

  • no hay datos manuales fuera de migraciones/seeders

Entonces sí:
👉 cada commit debería poder levantar la app como una “foto consistente” del sistema

Esto es el ideal del database versioning through migrations.


⚠️ Por qué en la práctica falla a menudo

1. Migraciones no reversibles o destructivas

Ejemplos problemáticos:

  • rename + código que aún espera el nombre viejo

  • drop column sin compatibilidad hacia atrás

  • cambios de tipo que rompen queries anteriores

👉 Rompen el “checkout histórico”.


2. Código depende de estado de datos, no del schema

Ejemplo:

  • un seeder cambió en un commit posterior

  • o datos manuales en dev que no están versionados

👉 El commit no es autosuficiente.


3. Seeders no deterministas

Si haces:

  • factory()->create() sin control

  • timestamps variables

  • datos externos (API, random sin seed fijo)

👉 el resultado cambia aunque el commit sea el mismo.


4. Falta de “reproducibilidad completa”

Laravel no garantiza automáticamente:

  • orden exacto histórico de migraciones

  • rollback perfecto de cambios complejos

  • compatibilidad entre versiones intermedias


5. Dependencia del entorno

  • MySQL vs PostgreSQL

  • versiones distintas del motor

  • charset/collation

  • config de Laravel


🧠 La idea clave

Lo que describes es un sistema tipo:

“cada commit es un snapshot ejecutable del sistema completo”

Eso es posible, pero solo si lo diseñas como:

👉 “migrations + seeders como sistema de reconstrucción determinista”

No como “historial evolutivo libre”.


🟢 Cómo hacerlo realmente robusto

Si quisieras acercarte al 100%:

  • migraciones solo additive o reversible

  • seeders versionados por estado (no acumulativos caóticos)

  • migrate:fresh --seed como única forma confiable de reconstrucción

  • evitar modificaciones destructivas en migraciones viejas

  • usar factories con seeds fijos (seed RNG controlado)


🔥 Conclusión

  • ✔️ Es una idea válida y muy potente

  • ⚠️ Pero solo funciona como garantía si impones disciplina fuerte

  • ❌ En la práctica, muchos proyectos rompen esa propiedad con el tiempo


Si quieres, puedo ayudarte a diseñar un workflow “tipo Git bisectable database”, donde realmente puedas moverte commit por commit sin romper nada.


Quiero renombrar 1 tabla. Estoy dudando entre por una parte tocar la migración de la tabla original y hacer como si se creó con el nuevo nombre desde la primera vez, y por otra parte hacer una migración distinta que renombre la tabla. No sé cuál elegir porque no entiendo bien las implicancias ni las preferencias o workflows establecidos por la comunidad de desarrollo.

La duda que tenés es muy común, y en realidad estás eligiendo entre dos filosofías distintas de migraciones.

Te explico claramente las implicancias de cada opción y qué se usa en la práctica.


🧭 Opción 1: Editar la migración original (reescribir historia)

👉 Cambiar la migración inicial para que la tabla “siempre haya tenido” el nuevo nombre.

❌ Problemas

  • Rompe el principio de inmutabilidad de migraciones

  • Si el proyecto ya está compartido o en producción:

    • otros desarrolladores ya ejecutaron la migración vieja

    • sus bases quedan desincronizadas

  • Git pierde valor como historial confiable de DB

  • No es reproducible hacia atrás

⚠️ Solo es aceptable si:

  • estás en desarrollo temprano

  • nadie más la ejecutó

  • puedes borrar toda la base sin consecuencias

👉 Esto es básicamente “resetear la historia”.


🧭 Opción 2: Crear una migración de rename (recomendado)

Schema::rename('old_table', 'new_table');

✅ Ventajas

  • Respeta el principio de append-only schema evolution

  • Funciona en equipos

  • Funciona en producción

  • Es reversible (down() puede revertir el rename)

  • Mantiene consistencia con el historial de DB

👍 Es el estándar de la comunidad

👉 En Laravel, este es el enfoque correcto casi siempre.


🧠 Regla de oro de la comunidad

“Las migraciones nunca se editan después de ser ejecutadas en entornos compartidos”

Se asume que:

  • cada migración es un “evento histórico”

  • la base de datos evoluciona, no se reescribe


⚖️ Comparación directa

CriterioEditar migraciónMigración de rename
Seguridad en equipo❌ Mala✅ Buena
Producción❌ Riesgoso✅ Correcto
Historial Git❌ Falso✅ Honesto
Reproducibilidad❌ Pierde consistencia✅ Mantiene consistencia
Uso recomendadosolo early devsiempre

🟢 Recomendación clara

👉 Usá migración de rename

Es la opción correcta en:

  • proyectos reales

  • equipos

  • apps que van a crecer

  • cualquier caso donde no quieras sorpresas


💡 Insight importante (la parte que te ayuda a decidir bien)

En migraciones, el objetivo no es “tener la base de datos más limpia posible”, sino tener una historia confiable de cambios ejecutables en cualquier momento.

Eso cambia completamente la forma de pensar:

  • No estás modelando “cómo debería verse la base ideal”

  • Estás modelando “cómo evolucionó la base en el tiempo”


🧠 Consecuencia clave

Editar una migración vieja equivale a decir:

“La historia nunca pasó así, en realidad pasó distinto”

Eso rompe un supuesto fundamental de los sistemas de migración:

👉 que el historial es reproducible


🔥 Por qué esto importa en la práctica

Imaginá este escenario real:

  • Dev A ejecutó migraciones hace 2 semanas

  • Dev B clona el repo hoy

  • Vos editás una migración vieja para renombrar una tabla

Resultado:

  • Dev A tiene una tabla con nombre viejo en su DB

  • Dev B crea la nueva versión

  • El código empieza a fallar de forma inconsistente

👉 Este tipo de divergencias son exactamente lo que las migraciones intentan evitar.


🟢 El principio profesional real

En equipos serios con Laravel o cualquier ORM:

“Si algo ya fue compartido o ejecutado, no se edita: se evoluciona”

Eso incluye:

  • renames

  • alter table

  • cambios de tipo

  • deletes

Todo eso se modela como nuevas migraciones.


⚖️ Regla mental simple

Te sirve como heurística:

  • 🟢 ¿Aún no se ejecutó en ningún lado? → podés editar

  • 🔴 ¿Ya se ejecutó en algún entorno? → no se toca, se migra


🧩 Conclusión final

En tu caso específico:

👉 renombrar una tabla = migración nueva con Schema::rename()

Es lo más seguro, estándar y compatible con workflows reales.


Si querés, en el próximo paso puedo ayudarte a ver algo más interesante:
👉 cómo diseñar migraciones para que sean “reordenables mentalmente” como un timeline sin generar deuda técnica.


Es un proyecto que yo considero muy pequeño y simple, que todavía no está ni cerca de ser desplegado en un ambiente compartido y por mucho tiempo será así ya que yo soy el único desarrollador. Estoy pensando que para un proyecto con tales características lo mejor es modificar directamente el archivo 2025_08_19_005459_create_odontogramas_table.php para fingir que la tabla fue creada con el nombre cambiado desde el principio y ejecutar un php artisan migrate:fresh. ¿Es esto muy aberrante en términos prácticas, metodologías o incluso workflows?

No, no es aberrante en absoluto. De hecho, en el contexto que describís, muchos desarrolladores harían exactamente eso.

La clave está en distinguir entre un proyecto en evolución temprana y un proyecto con historial que ya debe preservarse.

En tu caso, se cumplen prácticamente todas las condiciones para reescribir la historia:

  • ✅ Sos el único desarrollador.

  • ✅ No hay ambiente compartido.

  • ✅ No hay producción.

  • ✅ No necesitás preservar datos.

  • ✅ No te molesta ejecutar php artisan migrate:fresh.

En ese contexto, modificar:

2025_08_19_005459_create_odontogramas_table.php

para que cree la tabla con el nombre definitivo y luego ejecutar:

php artisan migrate:fresh

es una decisión perfectamente razonable.

De hecho, hay dos escuelas de pensamiento

1. Las migraciones como historia (la más difundida)

Una vez creada una migración, nunca se modifica. Se agregan nuevas migraciones.

Esta filosofía es ideal cuando ya existe una historia que preservar.

2. Las migraciones como descripción del estado inicial (muy usada en proyectos pequeños)

Mientras el proyecto está "en construcción", las migraciones se van corrigiendo para que reflejen la mejor versión del esquema. Cuando se necesita reconstruir la base, simplemente se hace:

php artisan migrate:fresh --seed

Esta filosofía evita acumular migraciones "de ruido", por ejemplo:

create_odontogramas_table
rename_odontogramas_to_odontograms
rename_odontograms_to_dental_charts
add_column_x
remove_column_x
rename_column_x

Cuando en realidad el proyecto nunca salió de desarrollo.

Mi criterio personal

Yo usaría esta regla:

  • Mientras no exista ningún entorno cuyo historial de migraciones deba respetarse, mantendría las migraciones limpias y editaría las existentes cuando eso haga que representen mejor el diseño actual.

  • A partir del momento en que exista un ambiente compartido, un cliente usando el sistema o simplemente quieras que el historial sea inmutable, dejaría de editar migraciones existentes y comenzaría a crear únicamente migraciones nuevas.

Es como si hubiera un punto de "congelamiento" del historial.

Una ventaja adicional

Si dentro de seis meses volvés a este proyecto y hacés:

php artisan migrate:fresh --seed

vas a obtener directamente el esquema definitivo, sin tener que ejecutar una larga cadena de migraciones cuyo único propósito fue corregir decisiones tomadas durante el diseño.


En resumen, con el estado actual de tu proyecto yo también modificaría la migración original. No lo considero una mala práctica; lo consideraría una mala práctica si siguieras haciéndolo después de que el proyecto tenga varios entornos, otros desarrolladores o datos que preservar. La diferencia no está en el código, sino en la etapa del ciclo de vida del proyecto.

No hay comentarios: