En este tutorial continuaremos con el proyecto que creamos en el post anterior "Construye SPAs sin necesidad de hacer una API con Inertia JS" y le agregaremos la funcionalidad para crear, editar y eliminar posts.

Paso 1:

Primero agregaremos Bootstrap a nuestra plantilla para darle un poco de estilo a nuestro sitio.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
    <link href="{{ mix('/css/app.css') }}" rel="stylesheet"></link>
    <script src="{{ mix('/js/app.js') }}" defer></script>
    <title>Inertia JS</title>

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <div class="row">
            @inertia
        </div>
    </div>

    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
app.blade.php

Paso 2:

Ahora debemos agregar el modelo y la migración para para almacenar los datos de nuestros posts, puedes hacerlo con el siguiente comando artisan make:model Post -m.

En la migración agregaremos tres campos: nombre, contenido y autor.

<?php

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

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('content');
            $table->string('author');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}
create_posts_table.php

Ejecutamos el comando artisan migrate para que la tabla se guarde en nuestra base de datos (dentro del archivo .env ya debes tener configurada tu conexión a la base de datos).

Ahora en el modelo agregaremos los mismos campos para habilitar la asignación masiva.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'content',
        'author',
    ];
}
Post.php

Paso 3:

Con el modelo ya creado el paso que sigue es crear el componente Vue para listar los posts y tener todas las acciones disponibles.

Para ello creamos el componente Index.vue dentro del directorio resources\js\Pages\Posts.

<template>

    <div class="col-md-6">
        <button class="btn btn-sm btn-primary w-100" @click="openModal()">Agregar nuevo</button>
        <table class="table table-bordered table-condensed">
            <thead>
            <tr>
                <td>Nombre</td>
                <td>Autor</td>
                <td>Acciones</td>
            </tr>
            </thead>
            <tr v-for="row in data">
                <td>{{row.name}}</td>
                <td>{{row.author}}</td>
                <td style="width: 130px">
                    <button @click="edit(row)" class="btn btn-sm btn-primary">Editar</button>
                    <button @click="deleteRow(row)" class="btn btn-sm btn-danger">Borrar</button>
                </td>
            </tr>
        </table>

        <div class="modal fade" id="modal">
            <div class="modal-dialog">

                <div class="modal-content">
                    <div class="modal-header">
                        <h4 class="modal-title">Nuevo post</h4>
                    </div>
                    <div class="modal-body">

                        <div class="form-group">
                            <label for="name">Nombre</label>
                            <input class="form-control" required id="name" v-model="form.name"/>
                        </div>
                        <div class="form-group">
                            <label for="content">Contenido</label>
                            <textarea class="form-control" required id="content" v-model="form.content"/>
                        </div>
                        <div class="form-group">
                            <label for="name">Autor</label>
                            <input class="form-control" required id="author" v-model="form.author"/>
                        </div>


                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" @click="closeModal()">Cerrar</button>
                        <button type="submit" class="btn btn-primary" v-show="!editMode" @click="save(form)">Guardar
                        </button>
                        <button type="submit" class="btn btn-primary" v-show="editMode" @click="update(form)">Actualizar
                        </button>
                    </div>
                </div><!-- /.modal-content -->

            </div><!-- /.modal-dialog -->
        </div><!-- /.modal -->

    </div>


</template>

<script>
export default {
    props: ['data'],
    data() {
        return {
            editMode: false,
            form: {
                name: null,
                content: null,
                author: null,
            },
        }
    },
    methods: {
        openModal: function () {
            $('#modal').modal('show')
        },
        closeModal: function () {
            $('#modal').modal('hide')
            this.reset();
            this.editMode=false;
        },
        reset: function () {
            this.form = {
                name: null,
                content: null,
                author: null,
            }
        },
        save: function (data) {
            this.$inertia.post('/posts', data)
            this.reset();
            this.closeModal();
            this.editMode = false;
        },
        edit: function (data) {
            this.form = Object.assign({}, data);
            this.editMode = true;
            this.openModal();
        },
        update: function (data) {
            if (!confirm('Sure')) return;
            data._method = 'PUT';
            this.$inertia.post('/posts/' + data.id, data)
            this.reset();
            this.closeModal();
        },
        deleteRow: function (data) {
            if (!confirm('Sure')) return;
            data._method = 'DELETE';
            this.$inertia.post('/posts/' + data.id, data)
            this.reset();
            this.closeModal();
        }
    }
}
</script>
Posts\Index.vue

Con esto ya tenemos listo el componente para administrar nuestros posts.

Paso 4:

El siguiente paso es agregar el controlador con las funciones para listar, crear, guardar, editar, actualizar y eliminar, puedes usar el comando artisan make:controller PostController --resource.

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;
use Inertia\Inertia;

class PostController extends Controller
{
    function index()
    {
        $data = Post::all();
        return Inertia::render('Posts/Index', ['data' => $data]);
    }

    public function store(Request $request)
    {
        Post::create($request->all());
        return redirect()->back();
    }

    public function update(Request $request)
    {
        if ($request->has('id')) {
            Post::find($request->input('id'))->update($request->all());
            return redirect()->back();
        }
    }

    public function destroy(Request $request)
    {
        if ($request->has('id')) {
            Post::find($request->input('id'))->delete();
            return redirect()->back();
        }
    }
}
PostController.php

Paso 5:

El último paso es crear la ruta para poder ingresar y administrar los posts en el archivo routes\web.php.

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\PostController;

Route::get('/', [HomeController::class, 'index'])->name('home');

Route::resource('posts',  PostController::class);
web.php

Y ahora solo ejecutamos el comando npm run development para compilar los componentes de Vue.

En las siguientes capturas les comparto el sitio funcionando:

Listado de posts
Agregar un post

Conclusión

Con InertiaJS podemos desarrollar mucho más rápido aplicaciones que normalmente necesitarían de una API sin perder las ventajas de usar Frameworks frontend.