Comunidad de diseño web y desarrollo en internet

Módulo de usuarios (VII): Eliminar un registro con Laravel

Esta es la última entrega sobre la serie cómo crear un módulo CRUD de usuarios, y en este último capítulo veremos cómo borrar un registro con Laravel, además usaremos jQuery y AJAX.

En los capítulos previos vimos:



Para hacer más sencillo este tutorial y en general casi cualquier problema, vamos a separar el proceso por partes. Primero vamos a aprender cómo borrar un registro sin AJAX.

En nuestro formulario de usuarios vamos a colocar lo siguiente:

app/view/admin/users/form.blade.php

Código :

@if ($action == 'Editar')  
{{ Form::model($user, array('route' => array('admin.users.destroy', $user->id), 'method' => 'DELETE', 'role' => 'form')) }}
  <div class="row">
    <div class="form-group col-md-4">
        {{ Form::submit('Eliminar usuario', array('class' => 'btn btn-danger')) }}
    </div>
  </div>
{{ Form::close() }}
@endif





Fíjense que como yo uso la misma plantilla para crear y para editar debo agregar el @if para que la opción de eliminar se muestre sólo si el usuario está trabajando sobre un registro existente.

El resto es similar a lo que ya hemos visto. Sólo que para construir la ruta se usa admin.users.destroy (destroy no delete) y el método es DELETE en vez de POST o PATCH.

También les he comentado que los navegadores no soportan sino los métodos GET y POST, pero Laravel y otros frameworks como Symfony (en realidad la idea viene de Symfony) emulan estos métodos usando un campo oculto _method por ejemplo. Siempre pueden ver código fuente (control + u en Chrome) para ver qué les generan los helper del framework que están usando.


Al hacer click sobre este botón no verán nada. Pero si vamos al controlador app/controllers/admin/UsersController.php y agregamos lo siguiente al método destroy:

Código :

   public function destroy($id)
   {
      return "Eliminando el registro $id";
   }


Entonces al cliquear eliminar verán un mensaje. Eso quiere decir que ya nuestra vista funciona. Ahora veamos cómo hacer para que el registro se borre realmente.

Hay 2 formas:

Código :

public function destroy($id)
{
        $user = User::find($id);
        
        if (is_null ($user))
        {
            App::abort(404);
        }
        
        $user->delete();

        return Redirect::route('admin.users.index');
}


Nos traemos el registro, verificamos que exista y por último llamamos al método delete.

La segunda es más sencilla:

Código :

public function destroy($id)
{
    User::destroy($id);

    return Redirect::route('admin.users.index');
}


Este método más simple sólo acepta como parámetro la ID de un registro, en este caso un usuario y borra el mismo.

A mí me gusta más el primer método porque es más orientado a objetos. Quizás además de borrar al usuario necesitemos borrar algunas imágenes asociadas a éste o hacer otra operación, en ese caso es más conveniente el primer método.

Si hacemos click en el botón eliminar seremos redireccionados a la lista pero veremos cómo el registro seleccionado antes fue eliminado.

Agregar la opción de eliminar a la lista


En views/admin/users/list.blade.php vamos a agregar un link que nos servirá para llamar el javascript para eliminar un registro:

Código :

          <a href="#" data-id="{{ $user->id }}" class="btn btn-danger btn-delete">
              Eliminar
          </a>


Este link lo van a agregar al lado del botón editar, de forma que quede así:



Ahora vamos a agregar al final de la misma plantilla, justo antes del @stop lo siguiente:

Código :

{{ Form::open(array('route' => array('admin.users.destroy', 'USER_ID'), 'method' => 'DELETE', 'role' => 'form', 'id' => 'form-delete')) }}
{{ Form::close() }}


Esto nos va a dar un form oculto que servirá para llamar a la acción de delete como en el ejemplo anterior, pero esta vez con javascript.

Noten que acá el ID lo dejé como un texto USER_ID, luego lo reemplazaré por el ID correcto, también con Javascript.

Ahora vamos a crear un nuevo archivo en public/assets/js/admin.js con lo siguiente:

Código :

$(window).ready(function () {
   
   if ( $ ('.btn-delete').length)
   {
       $('.btn-delete').click(function () {
          var id = $(this).data('id');
          $(this).parents('tr').fadeOut(1000); 
       });
   }

});


Y por supuesto tenemos que llamar al script, para ellos agreguemos:

Código :

{{ HTML::script('assets/js/admin.js') }}


En app/views/admin/layout.blade.php justo antes del </body>.

Si recargamos la lista y hacemos clic en el botón “eliminar” de cualquier usuario de la lista veremos cómo dicha fila se desvanece, esto gracias al jQuery, pero si presionamos F5 veremos que el usuario aún no ha sido eliminado, esto es porque aún falta:

Hacer la petición AJAX para eliminar el usuario


Primero vamos a adaptar nuestra acción de eliminar en app/controllers/admin/UsersController.php para que esté preparada para el AJAX:

Código :

   public function destroy($id)
   {
       $user = User::find($id);
        
        if (is_null ($user))
        {
            App::abort(404);
        }
        
        $user->delete();

        if (Request::ajax())
        {
            return Response::json(array (
                'success' => true,
                'msg'     => 'Usuario ' . $user->full_name . ' eliminado',
                'id'      => $user->id
            ));
        }
        else
        {
            return Redirect::route('admin.users.index');
        }
}


Las primeras líneas quedan igual, pero al final vamos a decidir que si la petición es AJAX if (Request::ajax()) vamos a devolver un JSON usando el método Response::json de Laravel, como parámetro vemos un array asociativo de PHP con alguna información que podría resultar útil para el frontend.

Luego vamos a cambiar nuestro script de admin.js por lo siguiente:

Código :

$(window).ready(function() {

   if ($('.btn-delete').length) {
      $('.btn-delete').click(function() {
         var id = $(this).data('id');
         var form = $('#form-delete');
         var action = form.attr('action').replace('USER_ID', id);
         var row =  $(this).parents('tr');
         
         row.fadeOut(1000);
         
         $.post(action, form.serialize(), function(result) {
            if (result.success) {
               setTimeout (function () {
                  row.delay(1000).remove();
                  alert(result.msg);
               }, 1000);                
            } else {
               row.show();
            }
         }, 'json');
      });
   }

}); 


Éste no es un tutorial de Javascript sin embargo les voy a explicar un poco qué hace el nuevo código de admin.js

Primero obtenemos el ID del registro que es muy importante, éste estaba en un atributo data del link para eliminar colocado en la lista anteriormente:

Código :

<a ... data-id="{{ $user->id }}" … >


Segundo obtenemos el objeto form con Jquery, al que se le asignó un ID de HTML “form-delete” anteriormente.

Código :

{{ Form::open(array(..., 'id' => 'form-delete')) }}


Luego usando este objeto form para obtener el valor del atributo “action” que nos dará la URL que tenemos que invocar para eliminar el registro, PERO recuerden que estábamos usando un “placeholder” USER_ID por eso lo reemplazamos por el ID real que queremos eliminar, obtenido previamente:

Código :

var action = form.attr('action').replace('USER_ID', id);


A continuación se obtiene la fila del registro en cuestión:

Código :

var row =  $(this).parents('tr')


$(this), en este caso corresponde al botón eliminar y el método “parents” de Jquery nos trae finalmente la fila donde se encuentra dicho botón, que es la fila (<tr>) del mismo usuario.

Luego desaparecemos la fila usando un efecto atractivo de jQuery:

Código :

row.fadeOut(1000);


Y abajo, el tan esperado método para eliminar la fila con AJAX:

Código :

$.post(action, form.serialize(), function (result) { //… }, 'json');


Vean que:
  • Como primer parámetro usamos la variable action que ya tendrá la URL correcta para eliminar el registro.
  • Como segundo parámetro serializamos los valores del form-delete (eso nos permite enviar los campos ocultos _method y el _csrf_token, necesarios para que la petición a Laravel sea válida).
  • El tercer parámetro es un callback que se ejecutará una vez que la llamada al servidor haya finalizado con éxito.
  • El cuarto parámetro le dice a Jquery que esperamos que la data obtenida de regreso esté en formato JSON.


Este callback tiene algo de código interesante que realmente no hace mucha falta, pero quiero que vean qué se puede hacer con la información retornada:

Código :

function(result) {
   if (result.success) {
      setTimeout(function() {
         alert(result.msg);
         row.delay(1000).remove();
      }, 1000);
   } else {
      alert (‘El registro ‘  + result.id + ‘ no pudo ser eliminado’);
      row.show();
   }
});


Podríamos por ejemplo tener un escenario donde el registro no sea eliminado (por falta de permisos o algo así), en ese caso podemos hacer que si “result.success” es falso, la fila vuelva a aparecer en la lista y se muestre un mensaje de error.

Si result.success es verdadero entonces también podemos mostrar un mensaje de éxito y eliminamos el HTML de la fila del código.

Lo importante es notar que podemos usar los datos de JSON que devolvimos desde nuestro controlador para alterar la vista, mostrar un mensaje etc.

En los próximos días publicaré un último tutorial con el indice de esta serie de tutoriales y además el código final completo.

Bonus track: la acción “show” para mostrar el usuario





Para quienes hicieron el ejercicio anterior, aquí tienen un ejemplo de cómo podría quedar la acción show:

Código :

   /**
    * Display the specified resource.
    *
    * @param  int  $id
    * @return Response
    */
   public function show($id)
   {
       $user = User::find($id);
        
        if (is_null($user)) App::abort(404);
        
      return View::make('admin/users/show', array('user' => $user));
   }


Y la vista app/views/admin/users/show.blade.php:

Código :

@extends ('admin/layout')

@section ('title') User {{ $user->full_name }} @stop

@section ('content')

<h2>User #{{ $user->id }}</h2>

<p>Full name: {{ $user->full_name }}</p>
<p>Email: {{ $user->email }}</p>

<p>
  <a href="{{ route('admin.users.edit', $user->id) }}" class="btn btn-primary">
    Editar
  </a>    
</p>

{{ Form::model($user, array('route' => array('admin.users.destroy', $user->id), 'method' => 'DELETE'), array('role' => 'form')) }}
  {{ Form::submit('Eliminar usuario', array('class' => 'btn btn-danger')) }}
{{ Form::close() }}

@stop

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate