¡La versión 2.0 de Play ya está lista! Ayúdanos a traducir la documentación de la útlima versión y sigue nuestro progreso.

Manuales, tutoriales & referencias

Consulte

Contenidos

Elija la versión

Buscar

Busque con google

Libros

Configuración básica de un área de administración usando CRUD

Por el momento, no tenemos ninguna forma de crear nuevos posts o moderar los comentarios a través de la interfaz de usuario del blog. Play provee un módulo CRUD, listo para usar, que nos ayudará a generar un área de administración básica.

Habilitar el módulo CRUD

Una aplicación Play puede estar compuesta por varios módulos. Esto permite reusar componentes en diferentes aplicaciones o separar una aplicación grande en varias más pequeñas.

El módulo CRUD es una aplicación genérica que realiza un análisis de las clases del modelo para crear listas y formularios sencillos.

Para habilitar el módulo CRUD, agregue la siguiente línea en el archivo /conf/dependencies.yml, después de require:

require:
    - play -> crud

Ahora ejecute el comando play dependencies para que play resuelva la nueva dependencia del módulo.

Este módulo viene con un conjunto genérico de routes que podemos reutilizar. Para importar estas routes sólo hay que agregar esta línea al archivo /yabe/conf/routes:

# Importar routes del módulo CRUD
*      /admin              module:crud

Esto importará todas las routes del módulo CRUD usando el prefijo /admin en las direcciones URL.

Tendrá que reiniciar la aplicación para poder utilizar el nuevo módulo.

Declarando los controladores de CRUD

Para cada objeto del modelo que deseemos incluir en el área de administración, deberemos declarar un controlador que herede del controlador controllers.CRUD. Esto es muy fácil.

Simplemente deberá crear un controlador por cada objeto del modelo. Por ejemplo, para el objeto Post crearemos el controlador Posts en el archivo /yabe/app/controllers/Posts.java.

package controllers;
 
import play.*;
import play.mvc.*;
 
public class Posts extends CRUD {    
}

Por convención, el controlador llevará como nombre el plural del objeto del modelo. De esta manera, Play encontrará automáticamente el objeto del modelo asociado a cada controlador. Si necesita utilizar un nombre diferente, puede hacerlo utilizando la anotación @CRUD.For. Para más información, consulte la documentación del módulo CRUD.

Haga lo mismo con todos los objetos del modelo:

package controllers;
 
import play.*;
import play.mvc.*;
 
public class Users extends CRUD {    
}
package controllers;
 
import play.*;
import play.mvc.*;
 
public class Comments extends CRUD {    
}
package controllers;
 
import play.*;
import play.mvc.*;
 
public class Tags extends CRUD {    
}

Ahora simplemente abra en su navegador http://localhost:9000/admin/, y debería poder acceder al área de administración.

A primera vista seguramente notará que los nombres de los objetos ciertamente podrían ser más descriptivos. Esto se debe a que por defecto Play utiliza el método toString() para obtener una representación legible de los objetos del modelo.

Podemos arreglarlo fácilmente agregando las implementaciones correctas del método toString() a todos los modelos. Por ejemplo, para la clase User:

…
public String toString() {
    return email;
}
…

Agregando validaciones

El problema principal de nuestra área de administración es que los formularios no contienen ninguna regla de validación. Pero afortunadamente, el módulo CRUD es capaz de extraer las reglas de validación directamente de las anotaciones de validación, en caso de que la clase del modelo cuente con ellas.

Agreguemos algunas anotaciones a la clase User:

package models;
 
import java.util.*;
import javax.persistence.*;
 
import play.db.jpa.*;
import play.data.validation.*;
 
@Entity
public class User extends Model {
 
    @Email
    @Required
    public String email;
    
    @Required
    public String password;
    
    public String fullname;
    public boolean isAdmin;
…

Si ahora te diriges al formulario de edición o creación del objeto User, verás que las reglas de validación son automáticamente agregadas al formulario:

Hagamos lo mismo con la clase Post:

package models;
 
import java.util.*;
import javax.persistence.*;
 
import play.db.jpa.*;
import play.data.validation.*;
 
@Entity
public class Post extends Model {
 
    @Required
    public String title;
    
    @Required
    public Date postedAt;
    
    @Lob
    @Required
    @MaxSize(10000)
    public String content;
    
    @Required
    @ManyToOne
    public User author;
    
    @OneToMany(mappedBy="post", cascade=CascadeType.ALL)
    public List<Comment> comments;
    
    @ManyToMany(cascade=CascadeType.PERSIST)
    public Set<Tag> tags;
…

Y chequea el resultado:

Aquí verá un efecto secundario interesante: la regla de validación @MaxSize cambió el modo en que Play muestra el formulario de los Post. Ahora utiliza un área de texto más grande para el campo del contenido.

Finalmente, podemos agregar reglas de validación también a las clases Comment y Tag:

package models;
 
import java.util.*;
import javax.persistence.*;
 
import play.db.jpa.*;
import play.data.validation.*;
 
@Entity
public class Tag extends Model implements Comparable<Tag> {
 
    @Required
    public String name;
…
package models;
 
import java.util.*;
import javax.persistence.*;
 
import play.db.jpa.*;
import play.data.validation.*;
 
@Entity
public class Comment extends Model {
 
    @Required
    public String author;
    
    @Required
    public Date postedAt;
     
    @Lob
    @Required
    @MaxSize(10000)
    public String content;
    
    @ManyToOne
    @Required
    public Post post; 
…

Mejorando las etiquetas del formulario

Como puedes ver, las etiquetas del formulario podrían ser más amigables. Por defecto, Play utiliza el nombre del campo Java como etiqueta del formulario. Para retocarlo, simplemente debemos especificar el texto de las etiquetas en el archivo /yabe/conf/messages.

De hecho, puedes tener un archivo messages distinto por cada lenguaje soportado por tu aplicación. Por ejemplo, podrías poner mensajes en Francés en el archivo /yabe/conf/messages.fr. Podrás ver como agregar localización de lenguajes en la parte 12: Internacionalización y localización.

Agrega estas etiquetas al archivo messages:

title=Title
content=Content
postedAt=Posted at
author=Author
post=Related post
tags=Tags set
name=Common name
email=Email
password=Password
fullname=Full name
isAdmin=User is admin

Ahora refresca cualquier formulario y verás las nuevas etiquetas:

Personalizando la lista de ‘Comentarios’

El módulo CRUD fue creado para ser totalmente personalizable. Por ejemplo, si miras la página de comentarios, la manera en que la información es mostrada en pantalla no es muy atractiva. Nos gustaría agregarle algunas columnas, especialmente la columna de ‘post relacionados’ para ayudarnos a filtrar la lista fácilmente.

De hecho, puedes sobreescribir cualquier action ó template provistos por el módulo CRUD. Por ejemplo, si quisieramos personalizar la vista de la ‘lista de comentarios’, simplemente deberíamos proveer otro template /yabe/app/views/Comments/list.html.

El módulo CRUD nos provee todavía más comandos Play cuando está habilitado. El comando crud:ov te ayudará a sobreescribir cualquier template. Desde la línea de comandos, tipea:

$ play crud:ov --template Comments/list

Con esto, tendrás un nuevo template en /yabe/app/views/Comments/list.html listo para que puedas modificarlo a gusto:

#{extends 'CRUD/layout.html' /}
 
<div id="crudList" class="${type.name}">
	
	<h2 id="crudListTitle">&{'crud.list.title', type.name}</h2>
 
	<div id="crudListSearch">
		#{crud.search /}
	</div>
 
	<div id="crudListTable">
		#{crud.table /}
	</div>
 	
	<div id="crudListPagination">
		#{crud.pagination /}
	</div>
	
	<p id="crudListAdd">
		<a href="@{blank()}">&{'crud.add', type.modelName}</a>
	</p>
 
</div>

Lo nuevo aquí es &{'crud.list.title', type.name}, que muestra el mensaje que tenga como clave a crud.list.title, pasando type.name como un parámetro del mensaje. El archivo de configuración del módulo CRUD contiene la entrada crud.list.title=&{%s}, en la cual el parámetro es utilizado a su vez como clave para acceder a otro mensaje relacionado, por ejemplo &{'Comments'} en éste caso, ya que type es un CRUD.ObjectType para models.Comments.

Por defecto, play simplemente mostrará la clave del mensaje - Comments, ya que no hemos definido una entrada con su correspondiente mensaje. Aprenderás más sobre mensajes localizados en la sección Internacionalización y localización al final de este tutorial.

El tag #{crud.table /} en realidad genera la tabla. Podemos personalizarla utilizando el parámetro fields para agregar más columnas. Prueba esto:

#{crud.table fields:['content', 'post', 'author'] /}

Y ahora tenemos tres columnas en la tabla:

El problema es que el campo de contenido content podría ser demasiado extenso en algunos comentarios. Por lo tanro, vamos a definir la manera en que el tag #{crud.table /} se las arregla para truncarlo según sea necesario.

Podemos definir una manera específica de mostrar cada campo utilizando el tag #{crud.custom /} de la siguiente manera:

#{crud.table fields:['content', 'post', 'author']}
 #{crud.custom 'content'}
  <a href="@{Comments.show(object.id)}">
   ${object.content.length() > 50 ? object.content[0..50] + '…' : object.content}
  </a>
 #{/crud.custom}
#{/crud.table}

Efectivamente, aquí Groovy aporta algo de su magia...

Personalizando el formulario ‘Post’

También podemos personalizar los formularios que hemos generado. Por ejemplo, la manera en que agregamos tags a un Post debería ser más simple. Podríamos construir algo mejor. Sobreescribamos el template Posts/show:

$ play crud:ov --template Posts/show

Ahora tienes un nuevo template en /yabe/app/views/Posts/show.html:

#{extends 'CRUD/layout.html' /}
 
<div id="crudShow" class="${type.name}">
	
<h2 id="crudShowTitle">&{'crud.show.title', type.modelName}</h2>
 
<div class="objectForm">
#{form action:@save(object.id), enctype:'multipart/form-data'}
    #{crud.form /}
    <p class="crudButtons">
        <input type="submit" name="_save" 
               value="&{'crud.save', type.modelName}" />
        <input type="submit" name="_saveAndContinue" 
               value="&{'crud.saveAndContinue', type.modelName}" />
    </p>
#{/form}
</div>
 
#{form @delete(object.id)}
    <p class="crudDelete">
        <input type="submit" value="&{'crud.delete', type.modelName}" />
    </p>
#{/form}
 
</div>

Puedes modificar el tag #{crud.form /} en Posts/show.html para modificar el campo tags agregando un tag crud.custom en el cuerpo del tag #{crud.form /}:

#{crud.form}
    #{crud.custom 'tags'}
        <label for="tags">
            &{'tags'}
        </label>
       	    <script type="text/javascript">
	        var toggle = function(tagEl) {
	            var input = document.getElementById('h'+tagEl.id);
	            if(tagEl.className.indexOf('selected') > -1) {
	                tagEl.className = 'tag';
	                input.value = '';
	            } else {
	                tagEl.className = 'tag selected';
	                input.value = tagEl.id;
	            }
	        }
	    </script>
	    <div class="tags-list">
	        #{list items:models.Tag.findAll(), as:'tag'}
	           <span id="${tag.id}" onclick="toggle(this)" 
	                class="tag ${object.tags.contains(tag) ? 'selected' : ''}">
	               ${tag}
	           </span> 
	           <input id="h${tag.id}" type="hidden" name="${fieldName}" 
	                    value="${object.tags.contains(tag) ? tag.id : ''}" />
	        #{/list}
	    </div>
    #{/crud.custom}
#{/crud.form}

Esto es un poco complicado y podríamos hacerlo mejor, pero ya tenemos un selector de tags mucho más simple utilizando un poquito de JavaScript:

Para mejorar la apariencia de la lista de tags, crea un nuevo archivo css en public/stylesheets/tags.css con el siguiente contenido:

.tags-list .tag {
     cursor: pointer;
     padding: 1px 4px;
}
.crudField .tags-list .selected {
     background: #222;
     color: #fff;
}

Luego, en views/CRUD/layout.html, cambia el bloque #{set 'moreStyles'} para que quede como el que sigue:

#{set 'moreStyles'}
    <link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/crud.css'}" />
    <link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/tags.css'}" />
#{/set}

¡Este es un buen comienzo para nuestra área de administración!

Continúa con: Agregando autenticación.