Gestión de usuarios en Rails: hacia SprintTracker v0.1
Ya me hago a la idea de lo que es una aplicación con Rails con suficiente claridad como para embarcarme en la tarea de crear la primera versión de SprintTracker. El objetivo de esta versión es que permita gestionar usuarios y proyectos, crear sprints asociados a proyectos, crear tareas dentro de un sprint y asignárselas a un desarrollador y por último ir añadiendo (re)estimaciones de la tarea durante los días que dura un sprint. La interfaz de usuario no me preocupa por ahora y dejaré la que genere Rails.
Primeros pasos
En primer lugar me decido probar un IDE específico de Ruby y encuentro RadRails así que digo adios a kate. También me pongo a buscar más artículos de Rails y me encuentro con una recopilación de los 12 mejores artículos de Ruby on Rails. A leer se ha dicho.
Una de las primeras cosas que se aprende de Rails es obliga a desarrollar de abajo a arriba: es decir empezando por el modelo de datos y llegando hasta la interfaz. Por ello es interesante comenzar la aplicación pensando bien el modelo de datos. El de SprintTracker es este:

Generación de código de persistencia en Rails
Rails ofrece dos modelos de generación de código (scaffolding) que podríamos denominar generación dinámica y generación por script
En la generación dinámica el desarrollador nunca llega a ver el código dado que este se genera en tiempo de ejecución. Un caso típico de uso sería ejecutar:
$ ruby script/generate controller User
que genera una serie de ficheros mínimos (sin código) para dar soporte a una herramienta de gestión de usuarios. Para añadir soporte de persistencia edito el fichero user_controller.rb generado y añado (en negrita):
class UserController < ApplicationController
scaffold :user
end
Tras hacer esto abro el navegador y voy a /user/list. Rails ha generado las pantallas y el código necesario para crear, listar, editar y borrar usuarios. Si tienes la oportunidad pruébalo, es muy impresionante.
La generación via script consiste en generar el código con la ejecución de un comando. El código se inserta en los ficheros de nuestro entorno y el desarrollador puede verlo y modificarlo. Siguiendo con el ejemplo anterior, para la herramienta de gestión de usuarios ejecutaría:
$ ruby script/generate scaffold User
Inicialmente me gustaba mucho más el primer modelo, sin embargo rápidamente me encontré con su principal inconveniente. La aplicación generada por defecto obligaba al usuario a introducir la contraseña cifrada (dado que es el campo que hay en base de datos) ¡y no parece haber ninguna manera de cambiarlo!
Esto me obligaba a usar la generación por script. A la generación de código de este tipo le veo dos inconvenientes fundamentales que también están presentes en Rails:
- Te obliga a entender el código que ha generado para poder modificarlo: afortunadamente es bastante fácil de entender con lo que no ha sido un problema tan grave
- Si lo modificas y cambias el modelo de datos no puedes regenerar sin perder los cambios
Sin embargo es la única opción que tenía porque necesitaba hacer cambios sobre lo generado. Leyendo el código generado y estudiando un poco la API de rails consigo crear una herramienta de gestión de usuarios en poco más de una hora.
Os muestro un par de ejemplos de cómo ha quedado. El formulario de creación y alta de usuarios es así:
<p><label for="user_login">Login</label><br/> <%= text_field 'user', 'login' %></p> <p><label for="user_password">Password</label><br/> <%= password_field 'user', 'password' %></p> <p><label for="user_password_confirmation">Password Confirmation</label><br/> <%= password_field 'user', 'password_confirmation' %></p>
Y la página de listado de usuarios así:
<table>
<tr>
<% for column in User.content_columns %>
<% unless (column.name == 'salt' or column.name == 'crypted_password') %>
<th><%= column.human_name%></th>
<% end %>
<% end %>
<th> </th>
<th> </th>
<th> </th>
</tr>
<% for user in @users %>
<tr class="<%= cycle("even", "odd") %>">
<% for column in User.content_columns %>
<% unless (column.name == 'salt' or column.name == 'crypted_password') %>
<td><%=h user.send(column.name) %></td>
<% end %>
<% end %>
<td><%= link_to 'Show', :action => 'show', :id => user %></td>
<td><%= link_to 'Edit', :action => 'edit', :id => user %></td>
<td><%= link_to 'Destroy', { :action => 'destroy', :id => user },
:confirm => 'Are you sure?' %></td>
</tr>
<% end %>
</table>
Y el resultado final:


Por cierto, las columnas updated_at y created_at las gestiona automáticamente Rails. Este es un ejemplo de como gracias a su especialización para crear aplicaciones web te ofrece ayudas muy concretas que ahorran bastante tiempo.
Conclusión
Con Rails voy más rápido de lo que puedo contarlo y ya tengo casi lista la versión 0.1. Mañana escribiré sobre como he implementado la gestión de proyectos, sprints, tareas y estimaciones y cómo establecer las relaciones entre ellas (con validación incluida).
Nota: Si vas a hacerte tu propia aplicación en Rails con gestión de usuarios hay extensiones al generador de código que generan una herramienta de gestión de usuarios completa con más funcionalidades que esta. Si por el contrario quieres aprender si me parece un buen ejercicio didáctico.

