En esta serie de 3 artículos, estaré haciendo un resumen de la demostración que realicé en el FLISOL Paraguaná 2009. Después de muchas vueltas, nunca logré ponerle un nombre bueno a la presentación, lo cual es algo que me decepciona. Mis amigos saben que me gusta ponerle nombres o títulos espaciales (si, con a no con e) a las cosas, por ejemplo, mi presentación del FLISOL pasado Entropía en el software, los cursos de Rails (Rails Sensei: Técnicas avanzadas y soluciones elegantes para la web). Pero en fin, aunque no fué el nombre que utilicé, vamos a conformarnos por ahora con Rails + iPhone.
No es usual en mí utilizar mucho texto en las presentaciones, pero si creen que les sirve de algo, o la quieren de recuerdo, pueden descargar la versión en pdf aquí.
Este primer artículo explicará lo que se desea hacer, se creará el proyecto y rápidamente generaremos un scaffold. La segunda parte consistirá en modificar un poco los estilos y ajustar el flujo de navegación, y la tercera parte consistirá en agregarle una interfaz para navegadores Mobile Safari (iPhone o iPod Touch).
Sé que muchos de los presentes ese día eran estudiantes, quizás no muy familiarizados con lo que es un Framework, con el patrón MVC, o con Ruby o Rails. La idea era demostrar lo rápido que era desarrollar una aplicación web con Rails y agregarle una interfaz específica para dispositivos móviles, en este caso un iPhone de Apple.
Después de una breve introducción, pudimos entrar en materia, crear la aplicación FLISOL To - do, una aplicación simple tipo to-do list. Así que entremos en materia nosotros también.
Una manera de definir lo que queremos hacer es diseñar la Interfaz Primero, preferiblemente con papel y lápiz (si, así de simple y barato) e ir planteando un flujo de la aplicación, por ejemplo: "hago clic aquí y se muestra tal cosa...", "clic en Aceptar para enviar los datos, luego se muestra el listado...". La idea es ir reflejando el flujo de trabajo del usuario con la aplicación. Este es el borrador de la interfaz para nuestro pequeño ejemplo.
Tenemos un título (Mis Tareas), que identifica toda nuestra interfaz, y claramente separamos las tareas Pendientes de las Finalizadas. Al hacer clic sobre un checkbox, indicamos si la tarea se terminó o la devolvemos al listado de pendientes. Adicionalmente incorporamos links para editar o eliminar cada una.
En la parte inferior se puede incorporar un formulario para agregar nuevas tareas. Se puede observar que la información asociada a una tarea incluye un Título y unas Notas. Por ejemplo:
- Título: Escribir segunda parte del artículo de Rails + iPhone.
- Notas: La segunda parte consta de aplicar los estilos y aplicar el flujo navegación detallado en la Parte 1.
Esto nos lleva al siguiente paso, definir un modelo inicial de datos para almacenar la información que deseamos mostrar. Al igual que antes, podemos usar lápiz y papel.
Sin mucho análisis, un buen nombre para nuestro modelo sería Tarea (luego veremos que por convenciones de Rails, la tabla asociada a un modelo, por defecto es plural, por eso la imagen muestra tareas). Tanto título como notas son atributos que deben aparecer en este modelo, pero también debemos agregar un mecanismo para determinar si cada tarea ya fue finalizada. Un nombre ideal para este atributo sería finalizada de tipo boolean, que permita indicar con true o false si la tarea en cuestión ya se culminó. Un detalle adicional aquí es que el atributo finalizada debe ser por defecto false (En un to-do list, no tiene sentido crear una tarea ya finalizada).
Con las ideas claras y un bosquejo de lo que queremos hacer, lo siguiente es crear el proyecto en Rails y comenzar a darle forma para que se parezca a nuestros borradores.
Para crear el proyecto, escribimos en la línea de comando:
rails flisol_todolist
cd flisol_todolist
La primera línea utiliza la instrucción de línea de comando rails, la cual nos permite inicializar un proyecto, con todos los directorios básicos y archivos de configuración necesarios para desarrollar la aplicación. rails crea el directorio flisol_todolist, que contiene todo el proyecto. Con la segunda línea, simplemente ingresamos a este directorio.
Ahora, podemos dar un paso rápido y crear un scaffold o bien crear "a mano" un Controlador para procesar los requests, un Modelo para gestionar el acceso a datos y darle persitencia a la información y luego agregar cada una de las vistas que nos permitirán mostrar la información en el navegador. Nos iremos por el camino rápido y crearemos un scaffold, que hará por nosotros todo lo antes mencionado. Antes, vamos a recordar que dijimos que el nombre de nuestro modelo sería Tarea y que tenía los atributos titulo, notas y finalizada.
Nos vamos a una terminal (la misma que teníamos abierta) y dentro del directorio del proyecto (flisol_todo) ejecutamos:
script/generate scaffold Tarea \
titulo:string \
notas:text \
finalizada:boolean
Lo que en realidad hicimos fue decirle al framework que generara un scaffold, es decir, una estructura base (de código fuente) de la cual podemos apoyarnos, para luego darle forma hasta convertirla en lo que realmente se ajusta a nuestras necesidades. Podemos notar que los argumentos son el nombre del modelo (Tarea en este caso) y sus atributos (los atributos son opcionales, pero en este ejemplo los incorporamos para yo no tener que escribir tanto en este artículo!!).
El Scaffold, aparte de crearnos el modelo Tarea (app/models/tarea.rb), el controlador TareasController (app/controllers/tareas_controller.rb) y las vistas principales (app/views/tareas), nos genera un migration, disponible en el directorio db/migrate/nnnn_create_tareas.rb (nnnn representa un timespamp). Por ahora vamos a conformarnos con saber que dicho migration nos permitirá especificar el esquema de la tabla asociada al modelo Tarea, es decir, el nombre de la tabla y sus columnas. Los migrations en Rails son extremadamente útiles, para mas información, pueden dirigirse a Rails Guides - Migrations. Vamos a darle una mirada a nuestro migration:
class CreateTareas < ActiveRecord::Migration
def self.up
create_table :tareas do |t|
t.string :titulo
t.text :notas
t.boolean :finalizada
t.timestamps
end
end
def self.down
drop_table :tareas
end
end
Nos enfocaremos solamente en la sección create_table :tareas ... end. En criollo, dice lo siguiente (omitiendo t.timestamps):
Crea la tabla tareas, con el campo titulo de tipo string, el campo notas de tipo text y el campo finalizada como boolean.
Si comparamos eso, con la imagen de nuestro modelo, que discutimos anteriormente, vemos que falta sólo algo, el valor por defecto (default), que debe ser false, para lo cual sólo debemos agregar :default => false al campo finalizada. El migration luego de editarlo queda de la siguiente manera:
class CreateTareas < ActiveRecord::Migration
def self.up
create_table :tareas do |t|
t.string :titulo
t.text :notas
t.boolean :finalizada, :default => false
t.timestamps
end
end
def self.down
drop_table :tareas
end
end
Antes de probar la aplicación, sólo nos queda crear la base de datos, la pregunta es ¿Si no hemos hablado si va a ser MySql, PostgreSql, SQLite, etc. Una ganancia de usar un framework (o mejor dicho un ORM) es tener la facilidad de hacer que nuestra aplicación sea en muchos casos database-agnostic, y Rails, o mejor dicho, ActiveRecord de Rails, es una de las cosas que nos permite hacer. Rails incluye una configuración de base de datos por defecto, la cual está basada en SQLite. Un extracto del archivo de configuración (config/database.yml) se muestra a continuación:
...
development:
adapter: sqlite3
database: db/development.sqlite3
pool: 5
timeout: 5000
...
Brevemente, adapter: sqlite3 indica que usaremos una base de datos SQLite 3.x y database: db/development.sqlite3 que está ubicada en el directorio db, con el nombre development.sqlite3.
Rails incluye un conjunto de tareas que nos permiten facilitar el trabajo con el (ejecutar rake -T para un listado), entre ellas la posibilidad de crear la base de datos y ejecutar los migrations de manera inteligente. Para crear la base de datos, con el esquema definido, ejecutamos en la terminal (si, en el directorio del proyecto) lo siguiente:
rake db:migrate
Listo! nuestra base de datos se creó en el directorio db, con el nombre development.sqlite3 (si no cambiaron el nombre y la ruta!!!). Si se genera algún tipo de error, revisar con tranquilidad los pasos anteriores, y todo el código escrito (:default => false jaja).
Para probar la aplicación, es necesario iniciar el servidor local, yo acostumbro abrir otra terminal (o pestaña) y utilizarla exclusivamente para el servidor de desarrollo, sólo recuerda verificar que estas en el directorio del proyecto. Para iniciar el servidor, ejecutar:
script/server
La salida indicará que el servidor inició y está escuchando en el puerto 3000, sólo nos queda disfrutar de la magia de Rails ingresando la url http://localhost:3000/tareas y jugar un poco agregando, modificando y eliminando tareas.
Si no probaron agregar una tarea con todos los campos en blanco, háganlo ahora, se darán cuenta de que no hay ninguna validación asociada. Como podrán imaginarse, el título debería ser requerido para cualquier tarea. Para lograr esto, editamos el archivo app/models/tarea.rb para que quede de la siguiente forma:
class Tarea < ActiveRecord::Base
validates_presence_of :titulo
end
Si volvemos a intentar ingresar una tarea sin especificar un título, obtendremos un mensaje de error, indicándonos que el título no puede estar en blanco. Para mas información sobre las validaciones, pueden ingresar en Rails Guides - ActiveRecord Validations and Callbacks.
Con esto, finalizamos la primera parte de esta serie de 3 artículos, en la siguiente entrega, ajustaremos el flujo de navegación y los estilos para que parezca mas un to-do list y en la tercera, mostraremos las tareas en un iPhone, utilizando rails_jqtouch.
Saludos!
¿Por qué utilizar un iPhone en vez de un BlackBerry o lo que sea?