10
SOLO PROGRAMADORES nº 153 54 REDES http://digital.revistasprofesionales.com Programación ágil con Ruby on Rails La escusa, los encuentros digitales La aplicación que vamos a desarrollar a lo largo del artículo sirve para gestionar encuentros digi- tales. Como es sabido, los encuentros digitales se organizan en sitios web, y permiten a los visitan- tes formular preguntas que, en un día y hora señalados, serán respondidas por un única perso- na, habitualmente famosa. Finalizado el encuen- tro, la lista de preguntas y respuestas queda dis- ponible para su posterior lectura. Por regla gene- ral las preguntas son filtradas o moderadas, según su pertinencia, y solo pueden ser respondidas por el famoso/a en cuestión. Pero nuestra aplicación será mucho más sencilla: cualquier usuario podrá crear, modificar o elimar encuentros y preguntas (véanse las figuras 1, 2 y 3). Entonces ¿qué sentido tiene un artículo que ilustre el desarrollo de una aplicación que no tiene nada del otro mundo? El objetivo, la programación ágil En la actualidad, conviven distintos paradigmas del desarrollo de aplicaciones. Algunas veces, la DABNE TECNOLOGÍAS DE LA INFORMACIÓN Programación ágil con Ruby on Rails Conflicto de intereses en un escenario conocido: el cliente presiona para conseguir cambios en la aplicación que se está desarrollando: desde su punto de vista los cambios son aspectos obvios, poca cosa. El desarrollador se resiste a aceptar esos cambios: es tirar por la borda trabajo ya realizado. El comercial también se resiste: cambios significa más tiempo, y más tiempo significa menos dinero. Estas tensiones, inevitables, se atenúan si disponemos de metodologías de desarrollo menos rígidas y de estructuras de soporte para la programación más productivas. Ruby on Rails es una de esas estructuras de soporte. Figura 1. La aplicación muestra la lista de encuentros, con la posibilidad de modificar o eliminar los encuentros creados, y de añadir uno nuevo. Figura 2. La vista de un encuentro muestra las preguntas y sus respuestas, si las hay, con la posiblidad de modificar o eliminar preguntas, y de añadir una nueva. Figura 3. El añadido de una pregunta no muestra una vista muy elaborada pero ¿cuántos minutos hemos empleado para conseguir que esta aplicación sea funcional?

Programación ágil con Ruby on Rails · revés, si Ruby on Rails convence, Ruby ya se aprenderá. Primer paso, crear la aplicación Para crear la aplicación, (véase figura 4) abri-

  • Upload
    phambao

  • View
    229

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Programación ágil con Ruby on Rails · revés, si Ruby on Rails convence, Ruby ya se aprenderá. Primer paso, crear la aplicación Para crear la aplicación, (véase figura 4) abri-

SOLO PROGRAMADORES nº 153 54

REDES

http://digital.revistasprofesionales.com

Programación ágilcon Ruby on Rails

La escusa, los encuentros digitales

La aplicación que vamos a desarrollar a lo largo

del artículo sirve para gestionar encuentros digi-

tales. Como es sabido, los encuentros digitales se

organizan en sitios web, y permiten a los visitan-

tes formular preguntas que, en un día y hora

señalados, serán respondidas por un única perso-

na, habitualmente famosa. Finalizado el encuen-

tro, la lista de preguntas y respuestas queda dis-

ponible para su posterior lectura. Por regla gene-

ral las preguntas son filtradas o moderadas, según

su pertinencia, y solo pueden ser respondidas por

el famoso/a en cuestión.

Pero nuestra aplicación será mucho más sencilla:

cualquier usuario podrá crear, modificar o elimar

encuentros y preguntas (véanse las figuras 1, 2 y

3). Entonces ¿qué sentido tiene un artículo que

ilustre el desarrollo de una aplicación que no tiene

nada del otro mundo?

El objetivo, la programación ágil

En la actualidad, conviven distintos paradigmas

del desarrollo de aplicaciones. Algunas veces, la

DABNE TECNOLOGÍAS DE LA INFORMACIÓN

Programación ágilcon Ruby on Rails

Conflicto de intereses en unescenario conocido: el clientepresiona para conseguir cambios enla aplicación que se estádesarrollando: desde su punto devista los cambios son aspectosobvios, poca cosa. El desarrolladorse resiste a aceptar esos cambios: estirar por la borda trabajo yarealizado. El comercial también seresiste: cambios significa mástiempo, y más tiempo significamenos dinero. Estas tensiones,inevitables, se atenúan sidisponemos de metodologías dedesarrollo menos rígidas y deestructuras de soporte para laprogramación más productivas.Ruby on Rails es una de esasestructuras de soporte.

Figura 1. La aplicación muestra la lista deencuentros, con la posibilidad de modificar oeliminar los encuentros creados, y de añadiruno nuevo.

Figura 2. La vista de un encuentro muestra laspreguntas y sus respuestas, si las hay, con laposiblidad de modificar o eliminar preguntas,y de añadir una nueva.

Figura 3. El añadido de una pregunta nomuestra una vista muy elaborada pero¿cuántos minutos hemos empleado paraconseguir que esta aplicación sea funcional?

REDES(ror) 21/9/07 14:26 Página 54

Page 2: Programación ágil con Ruby on Rails · revés, si Ruby on Rails convence, Ruby ya se aprenderá. Primer paso, crear la aplicación Para crear la aplicación, (véase figura 4) abri-

SOLO PROGRAMADORES nº 15355

REDES

http://digital.revistasprofesionales.com

Programación ágil con Ruby on Rails

especificación es lo más importante, y ceñir-

se a los requisitos es lo que conducirá al éxito

del proyecto. Si los planos son muy detalla-

dos, es posible seguirlos al milímetro. Pero

otras veces el usuario o promotor de la apli-

cación solo tiene una idea vaga de lo que

quiere. Parte de nuestro trabajo consistirá en

mostrarle posibilidades, opciones. En este

caso, estamos ante un proceso imprevisible,

que exige empezar a construir sin tener los

planos. ¿Qué hacer? Las métodologías ágiles

vienen en nuestra ayuda. En lugar de hacer

reuniones para hablar de cómo será la aplica-

ción, dediquemos ese tiempo a construir un

prototipo funcional que podamos mostrar en

acción al cliente, y sobre el que plantear

modificaciones y mejoras. En principio, como

idea, esto está muy bien. Pero ¿cómo hacerlo

sin que el presupuesto se dispare?

Ciertamente, uno de los inconvenientes de

las metodologías ágiles es que son caras. El

otro es que el cliente debe implicarse como

parte del equipo de desarrollo. Por eso, las

métodologías ágiles no siempre son adecua-

das pero, incluso cuando lo son, para que

sean operativas es necesario disponer de

estructuras de soporte a la programación.

Ruby on Rails es una de esas estructuras de

soporte.

El instrumento, Ruby on Rails

Ruby on Rails (RoR) es una estructura de

soporte (framework) para la programación

web desarrollada en lenguaje Ruby. Ruby es

un lenguaje de script, multiplataforma,

orientado a objetos. Y todo ello es software

libre. Ruby fue diseñado para un desarrollo

rápido y sencillo: sencillo por fuera pero

complejo por dentro. El lector encontrará

en la edición 149 de Sólo Programadores

un artículo de introducción a Ruby on Rails,

con indicaciones para instalarlo. El artículo

puede consultarse en la web de Dabne:

http://www.dabne.net/article104.html.

Damos por supuesto que el lector ya tiene

instalado Ruby on Rails, por lo que nos

ponemos manos a la obra en la creación

de la aplicación. No es preciso conocer

Ruby para seguir el artículo. Más bien al

revés, si Ruby on Rails convence, Ruby ya

se aprenderá.

Primer paso, crear la aplicación

Para crear la aplicación, (véase figura 4) abri-

mos “InstantRails.exe”, menú principal (botón

“I”), opción “Rails Applications...”. Pulsamos en

el botón “Create New Rails App...” y en la con-

sola que se abre ejecutamos:

rails encuentrosdigitales

El listado 1 muestra la lista de directorios

que se generan al crear la aplicación.

Entramos en el directorio recien creado

(véase figura 5):

cd encuentrosdigitales/

Ahí podemos ver la estructura de directorios

y ficheros creada por Rails para nuestra

nueva aplicación, tal como se muestra en el

listado 2.

Nota: Si por algún motivo hemos cerrado

InstanRails y queremos retomar el trabajo, al

volver a abrir InstantRails se debe pulsar en

el menú principal (icono “I”), opción “Rails

Applications” y luego “Open Ruby Console

Window”.

Con esto tenemos el esqueleto de nuestra

aplicación Rails, en el que todo tiene un sitio

predefinido. Al principio esta estructuración

puede parecer un engorro, pero luego se

agradece el no tener que pensar dónde hay

que poner cada fichero. El código de nuestra

aplicación irá dentro de “app”, los ficheros

estáticos (css, imágenes, javascripts, etc.)

irán en “public”, la configuración de la base

de datos en “config”, etc.

Rails viene con un servidor web incorporado

que podemos usar mientras desarrollamos.

Se trata de Mongrel. Para arrancar la aplica-

ción con Mongrel, desde InstantRails, menú

principal (botón “I”), “Rails Applications”,

Figura 4. Creación de la aplicaciónencuentrosdigitales.

Figura 5. Cambio de directorioencuentrosdigitales.

LISTADO 1 Creación de la aplicación

create create app/controllers create app/helpers create app/models create app/views/layouts create config/environments create components create db create doc create lib create lib/tasks create log create public/images create public/javascripts create public/stylesheets create script/performance create script/process create test/fixtures create test/functional create test/integration create test/mocks/development create test/mocks/test create test/unit create vendor create vendor/plugins create tmp/sessions create tmp/sockets create tmp/cache create tmp/pids create Rakefile create README create app/controllers/application.rbcreate app/helpers/application_helper.rbcreate test/test_helper.rb create config/database.yml create config/routes.rb create public/.htaccess create config/boot.rb create config/environment.rb create config/environments/production.rb create config/environments/development.rb create config/environments/test.rb create script/about create script/breakpointer create script/console create script/destroy create script/generate create script/performance/benchmarker create script/performance/profiler create script/process/reaper create script/process/spawner create script/process/inspector create script/runner create script/server create script/plugin create public/dispatch.rb create public/dispatch.cgi create public/dispatch.fcgi create public/404.html create public/500.html create public/index.html create public/favicon.ico create public/robots.txt create public/images/rails.png create public/javascripts/prototype.jscreate public/javascripts/effects.js create public/javascripts/dragdrop.js create public/javascripts/controls.js create public/javascripts/application.js create doc/README_FOR_APP create log/server.log create log/production.log create log/development.log create log/test.log

REDES(ror) 21/9/07 14:26 Página 55

Page 3: Programación ágil con Ruby on Rails · revés, si Ruby on Rails convence, Ruby ya se aprenderá. Primer paso, crear la aplicación Para crear la aplicación, (véase figura 4) abri-

SOLO PROGRAMADORES nº 153 56

REDES

http://digital.revistasprofesionales.com

“Manage Rails Applications...”, seleccionar

“encuentrosdigitales” y pulsar en “Start with

Mongrel” (véase figura 6). Se abrirá una con-

sola donde aparecerán los logs y el mensaje

de que pulsando Ctrl+C se cierra Mongrel.

Ahora, si vamos al navegador y tecleamos

http://localhost:3000/ en la barra de direc-

ciones veremos una página de bienvenida de

Rails, donde nos explica cuáles son los

siguientes pasos que deberemos dar (véase

figura 7).

Segundo paso, crear la base de datos

Creamos una base de datos para el desarro-

llo y un usuario asociado para acceder a ella.

En este caso usaremos MySQL pero podemos

usar otras como SQLite o Postgres. El set de

caracteres de la base de datos será utf8. Para

ello, en el directorio “InstantRails”, ejecuta-

mos las sentencias que se muestran en el lis-

tado 3. (Es preciso estar en una consola de

Ruby, que se pude abir desde el menú prin-

cipal de InstantRails, opción “Rails

Applications”, “Open Ruby Console Window”.

Observemos que el directorio actual será

“InstantRails/rails_app”, por lo que habrá

que moverse al directorio superior).

En realidad deberíamos crear tres bases de

datos, una para cada entorno de ejecución

de Rails: desarrollo (development), pruebas

(test) y producción (production). Rails incor-

pora el concepto de “entornos” para repre-

sentar las etapas del ciclo de vida de una

aplicación. El entorno se especifica en la

variable de entorno “RAILS_ENV”. Cada

entorno tiene su propia base de datos para

no interferir con los demás.

En desarrollo se recargan todas las clases

cada vez que se produce una llamada a una

acción, con lo que siempre se tienen carga-

dos los últimos cambios realizados, evitando

tener que reiniciar la aplicación. En produc-

ción se cargan las clases una sola vez bus-

cando la eficiencia. En desarrollo la aplica-

ción va mucho más lenta pero es más cómo-

da para el programador. En el entorno de

pruebas se cargan todos los datos de prue-

bas en la base de datos para cada prueba

que se ejecuta, independizando así los resul-

tados de unas y otras. Por este motivo hay

que tener una base de datos aparte para

pruebas, puesto que si no perderíamos todos

los datos que tuviesemos en la base de datos

cada vez que ejecutásemos las pruebas.

Cuando Rails genera un nuevo proyecto crea

un fichero llamado “database.yml” en el

directorio “config” con secciones para confi-

gurar cada una de las tres bases de datos.

Como Rails destruye todos los datos en la

base de datos de pruebas cada vez que se

ejecuta un test, hay que tener cuidado de no

poner la misma configuración en la de prue-

bas que en las otras.

Editamos el fichero “config/database.yml”

(véase listado 4) y modificamos los datos de

conexión a las bases de datos que acabamos

de crear. (El directorio debe ser

“InstantRails/rails_apps/encuentrosdigita-

les/config/”). Además, añadimos una línea

para indicarle a Rails que el set de caracteres

de la base de datos es UTF8. Dado que por

defecto los ficheros que genera Rails están

en utf8 esto es lo más recomendable.

Nota sobre la edición de ficheros: Como es

natural, los ficheros se pueden editar con

cualquier editor, pero es muy recomendable

que se guarden con la codificación UTF-8. El

bloc de notas de Windows tiene una opción

para ello.

Más convención y menos configuración

Ruby on Rails está construido siguiendo el

patrón Modelo-Vista-Controlador (MVC).

MVC es un patrón de diseño usado para

separar el modelo de datos de la aplicación,

la interfaz de usuario y la lógica de control

en tres capas diferentes con unas mínimas

dependencias entre ellas:

LISTADO 2 Estructura dela aplicación

. |— README |— Rakefile |— app | |— controllers | | `— application.rb | |— helpers | | `— application_helper.rb | |— models | `— views | `— layouts |— components |— config | |— boot.rb | |— database.yml | |— environment.rb | |— environments | | |— development.rb | | |— production.rb | | `— test.rb | `— routes.rb |— db |— doc | `— README_FOR_APP |— lib | `— tasks |— log | |— development.log | |— production.log | |— server.log | `— test.log |— public | |— 404.html | |— 500.html | |— dispatch.cgi | |— dispatch.fcgi | |— dispatch.rb | |— favicon.ico | |— images | | `— rails.png | |— index.html | |— javascripts | | |— application.js | | |— controls.js | | |— dragdrop.js | | |— effects.js | | `— prototype.js | |— robots.txt | `— stylesheets |— script | |— about | |— breakpointer | |— console | |— destroy | |— generate | |— performance | | |— benchmarker | | `— profiler | |— plugin | |— process | | |— inspector | | |— reaper | | `— spawner | |— runner | `— server |— test | |— fixtures | |— functional | |— integration | |— mocks | | |— development | | `— test | |— test_helper.rb | `— unit |— tmp | |— cache | |— pids | |— sessions | `— sockets `— vendor

`— plugins

Figura 6. Inicio de la aplicación con elservidor web Mongrel.

Figura 7. La aplicación en acción.

REDES(ror) 21/9/07 14:26 Página 56

Page 4: Programación ágil con Ruby on Rails · revés, si Ruby on Rails convence, Ruby ya se aprenderá. Primer paso, crear la aplicación Para crear la aplicación, (véase figura 4) abri-

SOLO PROGRAMADORES nº 153

� El controlador es el componente que reci-

be la petición del navegador y ejecuta la

acción especificada por el usuario.

� El modelo es la capa de datos que se usa,

generalmente desde el controlador, para

leer, añadir, modificar o borrar datos

almacenados, por ejemplo, en una base

de datos relacional.

� La vista es la representación de los datos

que el usuario ve en su pantalla.

ActiveRecord es el sistema de mapeo objeto-

relacional en Rails, la M en el patrón MVC. La

responsabilidad del modelo en el paradigma

MVC es ocuparse de la gestión del almace-

namiento de los datos de la aplicación. Sin

embargo, ActiveRecord es más que una sim-

ple librería para ejecutar queries SQL: auto-

máticamente mapea tablas de la base datos

con clases en la aplicación Rails, crea méto-

dos públicos para todos los campos de la

base de datos y añade muchos otros méto-

dos útiles para acceder los datos de la base

de datos.

Además, Rails hace suposiciones sobre los

nombres de las cosas. Por ejemplo, el nom-

bre del modelo es singular y la tabla que

contiene los datos de ese modelo tiene el

mismo nombre pero en plural. Si por alguna

razón no nos gusta que sea así es fácil

decirle a Rails que lo haga de otra forma. Si

creamos un “scaffold” a partir de un mode-

lo el controlador tendrá el nombre del

modelo pero en plural. (Un “scaffold” es un

“andamio” para nuestra aplicación. Es códi-

go generado para realizar las operaciones

básicas, como crear, editar y borrar registros,

con nuestros modelos.

Podríamos crear las tablas de nuestra base

de datos directamente con comandos SQL,

pero Rails tiene un sistema muy bueno, e

independiente del gestor de base de datos

que usemos, para definir la estructura de

nuestra base de datos, escribiéndola en Ruby

en los ficheros de “migraciones” y haciendo

que un adaptador la convierta a la sintaxis

adecuada para nuestro gestor de base de

datos. Además, de esta forma también pode-

mos mantener un histórico de los cambios

que vamos haciendo en la base de datos y

podemos avanzar o retroceder a la versión

que queramos fácilmente. También facilita el

despliegue en múltiples servidores de bases

de datos, si la aplicación llega a tener esas

dimensiones.

Las migraciones se pueden generar indepen-

dientemente o al crear cada modelo.

Tercer paso, crear el modelo

Empezamos con nuestra aplicación gene-

rando un modelo llamado “Encuentro” (en

una consola de Ruby, directorio “encuen-

trosdigitales”:

ruby script/generate model Encuentro

La salida será como se muestra en el listado 5.

La salida del comando de generación del

modelo será como se muestra en el listado 5.

Como podemos ver en la última línea, Rails

crea automáticamente una migración para

este modelo. Ahí es donde definimos los

campos que va a tener nuestra tabla en la

base de datos. El número 001 al principio del

nombre del fichero indica que es la primera

migración de esta aplicación.

Cuarto paso, crear la migración

Una migración tiene que implementar los

métodos “self.up” y “self.down”, que son

creados automáticamente al generar la

migración. El código que hay en “self.up” es

lo que se ejecuta al migrar la base de datos

a una versión superior, y el código en

“self.down” cuando migramos a una versión

inferior. En nuestra primera migración crea-

mos una tabla llamada “encuentros” y aña-

dimos columnas/campos para el nombre y

la descripción del encuentro. En “self.down”

simplemente borramos la tabla creada, para

el caso de que queramos volver a la versión

0, en la que la base de datos está vacía.

57

REDESProgramación ágil con Ruby on Rails

http://digital.revistasprofesionales.com

LISTADO 3 Creación de la bd de desarrollo

cd mysqlmysql -u rootCREATE DATABASE encuentrosdigitales_development CHARACTER SET utf8;GRANT ALL PRIVILEGES ON encuentrosdigitales_development.* TO usuario@localhost IDENTIFIED BY ‘solop’;exit

LISTADO 5 ruby script/generate model Encuentro

exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/encuentro.rb create test/unit/encuentro_test.rb create test/fixtures/encuentros.yml create db/migrate create db/migrate/001_create_encuentros.rb

LISTADO 4 database.yml

development: adapter: mysql database: encuentrosdigitales_development username: usuario password: solop host: localhostencoding: utf8

# Warning: The database defined as ‘test’ will be erased and # re-generated from your development database when you run ‘rake’. # Do not set this db to the same as development or production. test:

adapter: mysql database: encuentrosdigitales_test username: usuario password: solophost: localhostencoding: utf8

production: adapter: mysql database: encuentrosdigitales_production username: usuario password: solophost: localhostencoding: utf8

REDES(ror) 21/9/07 14:26 Página 57

Page 5: Programación ágil con Ruby on Rails · revés, si Ruby on Rails convence, Ruby ya se aprenderá. Primer paso, crear la aplicación Para crear la aplicación, (véase figura 4) abri-

SOLO PROGRAMADORES nº 153

Editamos el fichero “db/migrate/001_crea-

te_encuentros.rb” y añadimos los campos

que se muestran en el listado 6. Si ponemos

las columnas “created_at” y “updated_at”

con tipo “datetime” o “timestamp” en nues-

tra tabla, Rails se encargará de rellenarlas

automáticamente con los valores correctos.

Todas la tablas usadas por ActiveRecord

(excepto las tablas join) tienen que tener un

campo de clave primaria llamado id. No lo

especificamos en el código de la migración

porque Rails lo crea automáticamente a

menos que le indiquemos lo contrario (con

la opción “:id => false” al crear la tabla).

Para ver una descripción completa de las opcio-

nes disponibles en las migraciones, se puede

recurrir a la documentación disponible en

http://api.rubyonrails.org/classes/ActiveRecord/

Migration.html.

Ahora ejecutamos la tarea de migración de

la base de datos, para que Rails se encargue

de crear los campos que hemos especificado

(en el directorio “encuentros digitales”):

rake db:migrate

La salida del comando se muestra en la

figura 8.

Rails usa el entorno de desarrollo por defec-

to, con lo que los cambios se han hecho en

nuestra base de datos de desarrollo. Si que-

remos que se produzcan en otra base de

datos podemos especificar el entorno usando

la variable RAILS_ENV en el comando rake:

rake db:migrate RAILS_ENV=production

Rails también ha creado automáticamente

una tabla llamada “schema_info”. Esta tabla

tiene sólo un campo, “version”, cuyo valor

indica cuál es el número de migración

actual. Los scripts de migración usan este

dato para saber qué migraciones tienen que

ejecutar para poner todo al día.

Además, la migración crea un fichero llama-

do “db/schema.rb”, con el mismo formato

que los ficheros de migración, que describe

el estado actual de la base de datos en su

totalidad. Los scripts de migración mantie-

nen este fichero al día, con lo que no se

debería editar a mano.

Quinto paso, crear el scaffold

Como se ha mencionado anteriormente, un

“scaffold” es un “andamiaje” de nuestra apli-

cación. Es código generado para realizar las

operaciones básicas (crear, editar y borrar

registros) con nuestros modelos.

Generamos un “scaffold” para este modelo:

ruby script/generate scaffold Encuentro

La salida del comando puede verse en la

figura 9.

Ahora editamos el fichero “config/routes.rb”

(directorio “encuentrosdigitales”) para que por

defecto vaya al controlador encuentros, aña-

diendo, como se muestra en la figura 10, la

siguiente línea (alerta porque antes de la coma

hay dos comillas simples y no una doble):

map.connect ‘’, :controller => “encuentros”

El fichero “routes.rb” contiene las reglas para

el manejo de las URL, quitándole esta respon-

sabilidad al servidor web. Aplicando el princi-

pio de más convención y menos configura-

ción, Rails realiza una serie de mapeos conve-

cionales entre la vista y el controlador. Lo que

queremos conseguir con la línea anterior es

que cualquier petición de nuestra aplicación

se dirija al controlador “encuentros”.

Sexto paso, personalizar la vista

Eliminamos el fichero public/index.html, que es

donde está la página de bienvenida a Rails que

veíamos antes, y vamos a http://localhost:3000

58

REDES

http://digital.revistasprofesionales.com

LISTADO 6 001_create_encuentros.rb

class CreateEncuentros < ActiveRecord::Migration def self.up

create_table :encuentros do |t| t.column :nombre, :string t.column :descripcion, :text t.column :created_at, :datetime t.column :updated_at, :datetime

end end

def self.down drop_table :encuentros

end end

Figura 8. Migración del modelo.

Figura 9. Creación del scaffold para el modelo.

REDES(ror) 21/9/07 14:26 Página 58

Page 6: Programación ágil con Ruby on Rails · revés, si Ruby on Rails convence, Ruby ya se aprenderá. Primer paso, crear la aplicación Para crear la aplicación, (véase figura 4) abri-

SOLO PROGRAMADORES nº 153

en el navegador. Vemos la aplicación básica

que ha creado el scaffold (véase figura 11). Lo

que genera el scaffold es el punto de partida.

Ahora habrá que irlo modificando hasta que

nuestra aplicación tenga el aspecto deseado.

Los “layouts” se usan en Rails para poner en un

solo directorio el contenido común a todas las

vistas, como son la cabecera de la página y el pie.

Editamos “app/views/layout/encuentros.rhtml”

para añadirle una cabecera y algunas otras

cosillas (véase listado 7). Así tenemos una plan-

tilla general para todas las acciones, en la que

ponemos el código común a todas las vistas.

Luego con la llamada a “yield” incluimos el

contenido concreto de la vista correspondien-

te a la acción actual, que es lo que se encuen-

tra en cada uno de los ficheros rhtml que hay

en “app/views/encuentros/”.

Como queremos que esta plantilla sea para toda

la aplicación, no sólo para este controlador

renombramos el fichero “encuentros.rhtml”

como “application.rhtml”. Así se aplicará a todos

los controladores que no tengan su “layout”

específico (un fichero con nombre

“modelo_en_plural.rhtml” en el directorio

“app/views/layouts/”).

Añadimos estilos para la cabecera en

“public/stylesheets/scaffold.css”, como se

muestra en el listado 8. Esta parte ya depen-

de de las habilidades gráficas de cada uno y

no entra dentro del objetivo de este artículo,

así que lo dejaremos tirando a feote.

Cambiamos la vista del listado de encuentros,

que está en “app/views/encuentros/list.rhtml”,

para que se vea más clara, como se muestra

en el listado 9.

59

REDESProgramación ágil con Ruby on Rails

http://digital.revistasprofesionales.com

Figura 10. Asignando el control encuentros con edit, desde una consola, a la antigua usanza.

LISTADO 7 app/views/layout/encuentros.rhtml

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml” xml:lang=”es” lang=”es”> <head>

<meta http-equiv=”content-type” content=”text/html;charset=UTF-8” /> <title>Encuentros digitales</title> <%= stylesheet_link_tag ‘scaffold’ %>

</head> <body>

<div id=”cabecera”> <h1><%= link_to “Encuentros digitales”, :controller => ‘encuentros’ %></h1> </div>

<p style=”color: green”><%= flash[:notice] %></p>

<!—Content start—> <%= yield %> <!—Content end—>

<div id=”pie”>

</div>

</body> </html>

LISTADO 8 public/stylesheets/scaffold.css

#cabecera { background-color: lightblue; padding: 20px;

}

LISTADO 9 app/views/encuentros/list.rhtml

<% for encuentro in @encuentros %> <p> <%= link_to encuentro.nombre, :action => ‘show’, :id => encuentro %> <%= link_to image_tag(‘edit.gif’), :action => ‘edit’, :id => encuentro %> <%= link_to image_tag(‘delete.gif’), { :action => ‘destroy’, :id => encuentro }, :confirm => ‘¿Seguro?’, :method => :post %> <br> <%= encuentro.descripcion %> </p>

<% end %>

<%= link_to ‘Anterior’, { :page => @encuentro_pages.current.previous } if @encuentro_pages.current.previous %> <%= link_to ‘Siguiente’, { :page => @encuentro_pages.current.next } if @encuentro_pages.current.next %>

<p> <%= link_to ‘Nuevo encuentro’, :action => ‘new’ %> </p>

Figura 11. La aplicación, tal como la hacreado el scaffold.

REDES(ror) 21/9/07 14:26 Página 59

Page 7: Programación ágil con Ruby on Rails · revés, si Ruby on Rails convence, Ruby ya se aprenderá. Primer paso, crear la aplicación Para crear la aplicación, (véase figura 4) abri-

SOLO PROGRAMADORES nº 153

Como se puede ver hemos puesto imágenes

en lugar de textos en los enlaces para las

acciones de editar y borrar, con lo que ahora

hay que poner en el directorio “public/images”

los ficheros “edit.gif” y “delete.gif” correspon-

dientes. En Internet hay multitud de iconos

gratis e incluso libres que podemos usar, y

además el lector puede encontrar estos fiche-

ros en el cd-rom.

Ahora vamos a editar la vista de creación de

nuevo encuentro, para quitarle al formulario los

campos correspondientes a las marcas de tiem-

po de creación y actualización, ya que Rails se

encarga de rellenarlos automáticamente.

Editamos “app/views/encuentros/new.rhtml”

y “app/views/encuentros/edit.rhtml” para

poner los textos en castellano, como se

muestra en los listados 10 y 11.

Como podemos observar, los campos del

formulario no están en ninguno de estos

ficheros y en su lugar tenemos una línea:

<%= render :partial => ‘form’ %>

Esto lo que hace es incluir el contenido del

fichero “_form.rhtml” en ese punto, de

forma que se pueden reutilizar trozos de

código en las vistas. En este caso, ya que el

formulario es el mismo para las dos accio-

nes, está contenido en un “partial” que se

incluye desde sus vistas. Obsérvese que el

nombre de fichero de un “partial” lleva un

guión bajo delante, mientras que en la lla-

mada desde la vista sólo se pone el nombre,

sin extensión y sin guión.

Del fichero “app/views/encuentros/

_form.rhtml” borramos las líneas que se

muestran en el listado 12 y lo dejamos

como se muestra en el listado 13.

Séptimo paso, pulir

Con esto ya podemos crear, modificar y borrar

encuentros, pero quedan algunas cosas por pulir.

Por ejemplo, podríamos crear un encuentro con

todos los campos vacíos (menos el “id” que crea

automáticamente Rails), pero eso es algo que no

queremos. Para evitar eso tenemos algo muy

potente en los modelos, que son las validaciones.

Con un par de líneas podemos hacer que nues-

tro modelo no acepte campos vacíos, o que com-

pruebe la longitud de los textos.

En nuestro ejemplo queremos que todo encuen-

tro tenga un nombre y que ese nombre no exce-

da de los 255 caracteres, que es el tamaño por

defecto del string que hemos puesto antes al

definir los campos de la tabla “encuentros” en la

migración. Eso lo conseguimos añadiendo en

“app/models/encuentro.rb” las dos líneas que, en

el listado 14, se muestran en negrita.

Ahora, si intentamos crear un encuentro con el

nombre vacío nos saldrá un error que nos expli-

ca qué ha pasado y nos vuelve a pedir los datos.

De vuelta al paso tres

Nuestra aplicación tiene encuentros pero no

tiene preguntas. Creamos el modelo

“Pregunta” (véase figura 12):

ruby script/generate model Pregunta

La salida del comando se muestra en el lis-

tado 15.

Y al paso cuatro

Editamos la migración “db/migrate/002_cre-

ate_preguntas.rb”, añadiendo las líneas que

en el listado 16 se muestran en negrita. Cada

pregunta pertenece a un encuentro, por lo

60

REDES

http://digital.revistasprofesionales.com

LISTADO 11 app/views/encuentros/edit.rhtml

<h1>Edición del encuentro</h1>

<% form_tag :action => ‘update’, :id => @encuentro do %><%= render :partial => ‘form’ %><%= submit_tag ‘Editar’ %>

<% end %>

<%= link_to ‘Mostrat’, :action => ‘show’, :id => @encuentro %> |<%= link_to ‘Volver’, :action => ‘list’ %>

LISTADO 13 app/views/encuentros/_form.rhtml, final<%= error_messages_for ‘encuentro’ %>

<!—[form:encuentro]—> <p><label for=”encuentro_nombre”>Nombre</label><br/> <%= text_field ‘encuentro’, ‘nombre’, :size => “70” %></p>

<p><label for=”encuentro_descripcion”>Descripción</label><br/> <%= text_area ‘encuentro’, ‘descripcion’, :cols => “80”, :rows => “5” %></p>

<!—[eoform:encuentro]—>

LISTADO 14 app/models/encuentro.rb

class Encuentro < ActiveRecord::Base validates_presence_of :nombre validates_length_of :nombre, :maximum => 255

end

LISTADO 12 app/views/encuentros/_form.rhtml, borrar

<p><label for=”encuentro_created_at”>Created at</label><br/> <%= datetime_select ‘encuentro’, ‘created_at’ %></p>

<p><label for=”encuentro_updated_at”>Updated at</label><br/> <%= datetime_select ‘encuentro’, ‘updated_at’ %></p>

Figura 12. ruby script/generate model Pregunta.

LISTADO 10 app/views/encuentros/new.rhtml

<h1>Nuevo encuentro</h1>

<% form_tag :action => ‘create’ do %><%= render :partial => ‘form’ %><%= submit_tag “Crear” %>

<% end %>

<%= link_to ‘Volver’, :action => ‘list’ %>

REDES(ror) 21/9/07 14:26 Página 60

Page 8: Programación ágil con Ruby on Rails · revés, si Ruby on Rails convence, Ruby ya se aprenderá. Primer paso, crear la aplicación Para crear la aplicación, (véase figura 4) abri-

SOLO PROGRAMADORES nº 153

que ponemos una referencia al encuentro

correspondiente.

Ejecutamos la migración (véase figura 13):

rake db:migrate

Y al paso cinco

Creamos el “scaffold”, respondiendo “n” a la

pregunta “overwrite public/stylesheets/scaf-

fold.css? [Ynaqd]” (véase figura 14):

ruby script/generate scaffold Pregunta

Cuando pregunte si sobreescribir el fichero

“public/stylesheets/scaffold.css” decimos que

no porque lo hemos modificado antes para

incluir los estilos de la cabecera y si lo sobre-

escribimos perderíamos dichos cambios.

Saltamos el paso seis

También se ha generado un “layout” para

este controlador, pero como queremos que

use el general tenemos que borrar el fichero

“app/views/layouts/preguntas.rhtml”.

Y seguimos por el paso siete, pulir

Añadimos las relaciones y las validaciones a

los modelos en “app/models/encuentro.rb” y

“app/models/pregunta.rb”, como se muestra

en las líneas en negrita de los listados 17 y

18. De esta manera, nos aseguramos de que

se rellene el campo pregunta y el encuentro

al que pertenece la pregunta.

Después de todo esto, si vamos a

http://localhost:3000/preguntas y creamos

una nueva pregunta vemos que no hay

forma de relacionarla con un encuentro.

Para eso editamos el fichero “app/views/pre-

guntas/_form.rhtml” y añadimos el campo al

formulario, agregando las dos líneas que en

el listado 19 se muestran en negrita.

Como en las vistas no debe ir nada de la

lógica de la aplicación, la función que gene-

ra la lista de encuentros para el desplegable

la ponemos en “app/helpers/preguntas_hel-

per.rb”, como se muestra en el listado 20.

Al generar el “scaffold” de un modelo se crea un

fichero llamado “modelo_helper.rb” en “app/hel-

pers”, donde podemos poner las funciones auxi-

liares que necesitemos usar en nuestras vistas. Si

hace falta que una de estas funciones o “helpers”

sea accesible desde las vistas de varios modelos

hay que ponerla en “application_helper.rb”.

Los helpers son útiles para mantener las vistas

limpias y fáciles de leer. Las vistas no deberían

contener lógica compleja. Si la hay, ésta se

debería refactorizar y moverla a un helper. Los

métodos de la clase “helper” se pueden llamar

desde la vista.

Ahora vamos a modificar la vista

“app/views/encuentros/show.rhtml” para

que se vean todas las preguntas asociadas a

ese encuentro, como se muestra en el lista-

do 21. Después de cada pregunta ponemos

un icono con un enlace para editar la pre-

gunta y añadirle una respuesta y otro para

borrar la pregunta.

Para que al editar la respuesta y darle a guar-

dar vuelva a la pantalla anterior, modificamos

la redirección en el método “update” del con-

trolador (“app/controllers/preguntas_contro-

ller.rb), sustituyendo la línea “redirect_to” por la

que se muestra en negrita en el listado 22. En

el mismo fichero, en el método “destroy”, tam-

bién sustituimos la línea “redirect_to” por la

que en el listado 23 se muestra en negrita. Para

no perder el encuentro al que pertenecía la

pregunta lo guardamos en una variable “e”.

Siguiendo en el mismo fichero (app/contro-

llers/preguntas_controller.rb), para que al pin-

char en “Añadir pregunta” aparezca seleccio-

61

REDESProgramación ágil con Ruby on Rails

http://digital.revistasprofesionales.com

Figura 13. Ejecución de la migración.

Figura 14. Creación de scaffold para el modelo.

LISTADO 16 db/migrate/002_create_preguntas.rb

class CreatePreguntas < ActiveRecord::Migration def self.up

create_table :preguntas do |t| t.column :pregunta, :text t.column :respuesta, :text t.column :encuentro_id, :integer t.column :created_at, :datetime t.column :updated_at, :datetime

end end

def self.down drop_table :preguntas

end end

LISTADO 15 ruby script/generate model Pregunta

exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/pregunta.rb create test/unit/pregunta_test.rb create test/fixtures/preguntas.yml exists db/migrate create db/migrate/002_create_preguntas.rb

REDES(ror) 21/9/07 14:26 Página 61

Page 9: Programación ágil con Ruby on Rails · revés, si Ruby on Rails convence, Ruby ya se aprenderá. Primer paso, crear la aplicación Para crear la aplicación, (véase figura 4) abri-

SOLO PROGRAMADORES nº 153

nado el encuentro desde el que hemos pin-

chado añadimos un parámetro “:encuentro_id

=> @encuentro” al enlace y en el método

“new” lo asignamos al objeto pregunta, como

se muestra en la línea en negrita del listado 23.

De nuevo en el mismo fichero, para que al

crear la pregunta vuelva a la pantalla del

encuentro, no a la lista general de todas las

preguntas modificamos la redirección en el

método create, como como se muestra en la

línea en negrita del listado 24.

Ya que estamos editando el controlador

podemos aprovechar y cambiar los textos en

inglés por unos en castellano:

flash[:notice] = ‘Pregunta creada

correctamente.’

flash[:notice] = ‘Pregunta actualizada

correctamente.’

Conclusiones

En este momento del desarrollo de la apli-

cación, el lector puede manejar encuen-

tros digitales y, para cada encuentro, pre-

guntas. Es cierto que en vista de los

encuentros los mensajes se han puesto en

español y se han eliminado los campos

“Created at” y “Updated at”, cosa que no se

ha hecho con las preguntas, así que esta

sería una buena manera de seguir pulien-

do la aplicación.

Por motivos de espacio y de simplicidad se

ha omitido la validación de usuarios, pero el

objetivo no es tanto desarrollar una aplica-

ción como mostrar la manera de desarro-

llarla, al estilo Ruby on Rails. Con RoR, en

cuestión de minutos disponemos de una

aplicación operativa que empezamos a pulir,

y que vamos mejorando mientras el tiempo

62

REDES

http://digital.revistasprofesionales.com

LISTADO 18 app/models/pregunta.rbclass Pregunta < ActiveRecord::Base

belongs_to :encuentro validates_presence_of :pregunta , :encuentro_id

end

LISTADO 17 app/models/encuentro.rbclass Encuentro < ActiveRecord::Base

has_many :preguntas

validates_presence_of :nombre validates_length_of :nombre, :maximum => 255

end

LISTADO 22 app/controllers/preguntas_controller.rb, update

def update @pregunta = Pregunta.find(params[:id]) if @pregunta.update_attributes(params[:pregunta])

flash[:notice] = ‘Pregunta actualizada correctamente.’ redirect_to :controller => ‘encuentros’, :action => ‘show’, :id => @pregunta.encuentro

else render :action => ‘edit’

end end

LISTADO 20 app/helpers/preguntas_helper.rb

module PreguntasHelper def encuentros

Encuentro.find(:all).collect {|p| [ p.nombre, p.id ] } end

end

LISTADO 19 app/views/preguntas/_form.rhtml

<%= error_messages_for ‘pregunta’ %>

<!—[form:pregunta]—>

<p><label for=”pregunta_encuentro_id”>Encuentro</label><br/> <%= select ‘pregunta’, ‘encuentro_id’, encuentros %></p>

<p><label for=”pregunta_pregunta”>Pregunta</label><br/> <%= text_area ‘pregunta’, ‘pregunta’, :cols => “80”, :rows => “5” %></p>

<p><label for=”pregunta_respuesta”>Respuesta</label><br/> <%= text_area ‘pregunta’, ‘respuesta’, :cols => “80”, :rows => “5” %></p>

<!—[eoform:pregunta]—>

LISTADO 21 app/views/encuentros/show.rhtml

<h2><%=h @encuentro.nombre %></h2> <p><%=h @encuentro.descripcion %></p>

<h3>Preguntas: </h3>

<ul> <% for p in @encuentro.preguntas %> <li> <strong><%= p.pregunta %></strong> <%= link_to image_tag(‘edit.gif’), :controller => ‘preguntas’, :action => ‘edit’, :id => p %> <%= link_to image_tag(‘delete.gif’), {:controller => ‘preguntas’, :action => ‘destroy’, :id => p }, :confirm =>‘¿Seguro?’, :method => :post %> <br> <%= p.respuesta %> </li> <% end %> </ul>

<%= link_to “Añadir una pregunta”, :controller => ‘preguntas’, :action => ‘new’, :encuentro_id => @encuentro %>

REDES(ror) 21/9/07 14:26 Página 62

Page 10: Programación ágil con Ruby on Rails · revés, si Ruby on Rails convence, Ruby ya se aprenderá. Primer paso, crear la aplicación Para crear la aplicación, (véase figura 4) abri-

SOLO PROGRAMADORES nº 153

y el presupuesto lo permiten. Desde la expe-

riencia de dabne.net, Ruby on Rails aporta la

posibilidad concreta y material de desarro-

llar según metodologías ágiles que integran

los cambios en la especificación no como un

escollo o un paso atrás sino como algo

inherente al proceso de comunicación en el

que comerciales, técnicos, clientes y usua-

rios estamos implicados.

63

REDESProgramación ágil con Ruby on Rails

http://digital.revistasprofesionales.com

LISTADO 24 app/controllers/preguntas_controller.rb, createdef create

@pregunta = Pregunta.new(params[:pregunta]) if @pregunta.save

flash[:notice] = ‘Pregunta was successfully created.’ redirect_to :controller => ‘encuentros’, :action => ‘show’, :id => @pregunta.encuentro

else render :action => ‘new’

end end

LISTADO 23 app/controllers/preguntas_controller.rb, newdef new

@pregunta = Pregunta.new @pregunta.encuentro_id = params[:encuentro_id]

end

LISTADO 22 app/controllers/preguntas_controller.rb, destroydef destroy

p = Pregunta.find(params[:id]) e = p.encuentro p.destroy redirect_to :controller => ‘encuentros’, :action => ‘show’, :id => e

end

Conferencia Hispana Rails 2007Durante el próximo mes de

noviembre se celebrará en

Madrid la II Conferencia

Hispana Rails (www.confe-

renciarails.org/). De entre

las propuestas de ponencia

recibidas hasta el momento

destacamos estas:

� APIs de Identidad y RailsIntroducción en el mundo

de las APIs más populares

de la red como Flickr,

Last.fm/Audiscrobbler o

GoogleMaps.

� APIs Rest y proxificaciónIntroducción a las APIs

Rest y qué pueden aportar

a nuestras aplicaciones.

� BDD y rSpecAdemás del desarrollo

guiado por tests, existe otro

paradigma que va un paso

más allá de éste: el desarro-

llo orientado a comporta-

miento.

� Caché en RailsMecanismos para intro-

ducir caché en las diferen-

tes capas por las que

transcurre la resolución de

una petición.

� Camping, el microfra-meworkPara qué podríamos que-

rer usar Camping y cómo

hacerlo.

� Cómo programar unaaraña web con RailsTaller práctico en el que se

explicará cómo construir

desde cero una araña web.

� Flickr con RailsTaller práctico para cons-

truir una interfaz interac-

tiva con el servicio Flickr.

� Integración de Rails enel escritorio con SlingshotSlingshot es la alternativa

Open Source propuesta por

Joyent a los recientes desa-

rrollos de Microsoft y

Adobe para integrar aplica-

ciones web en el escritorio

usando Ruby on Rails.

� Inteligencia artificial apli-cada a la publicidad con RubyCómo utilizar la inteligen-

cia artificial en Ruby on

Rails para optimizar auto-

máticamente la publici-

dad de una aplicación.

� Introducción a RubyStackPresentación y demostra-

ción de RubyStack, una dis-

tribucion integrada Open

Source de Ruby on Rails.

� JRuby on Rails:Agilidad en la empresaJRuby on Rails proporciona

la agilidad de Rails sobre ser-

vidores y aplicaciones Java.

� La internacionaliza-ción sí es posibleAunque Rails no tiene sopor-

te incorporado para la inter-

nacionalización, hay muchas

opciones para abrir las puer-

tas de una aplicación a

audiencias más grandes.

� Más allá del testingVale. Tests. Sabes que los

necesitas, sabes que tienes

que hacerlos. Pero, ¿por

dónde empezar? ¿Qué tal

especificar el comporta-

miento de tu aplicación en

forma de tests?

� Phobos: scripting de ser-vidor para plataforma JavaPhobos es un en entorno

de aplicaciones ligero con

el rendimiento, escalabili-

dad y fiabilidad de la plata-

forma Java.

� Programa en Railscomo si jugases con LegoCómo funcionan los plug-

ins de Rails y cómo pode-

mos crear nuestros propios

plug-ins.

� Proyectos de bajo costecon limitaciones severasde tiempo y recursosExisten aplicaciones cuyo

desarrollo se plantea con una

limitación de tiempo y recur-

sos severa. Rails nos ayuda.

� Rails against the machineCómo crear entornos vir-

tuales clonables para el des-

pliegue de aplicaciones Rails

con Capistrano 2 y XEN.

� Rails desde el códigoBajaremos a las entrañas de

Rails y echaremos un vista-

zo a la implementacion del

framework.

� Rails para torpes como yoEs difícil transmitir qué es

Ruby on Rails y qué signi-

fica que nos guste y que

estemos felices por pro-

gramar en este lenguaje.

� Rails y Globalize: un trencon destinos internacionalesCómo Globalize puede

enseñar a tu aplicación Rails

monolingüe a aprender

idiomas.

� Seguridad web enaplicaciones RailsUn repaso a la seguridad

web y a algunas de las vul-

nerabilidades más comunes.

� Tractis, un enfoquetécnicoCon un enfoque lo más

técnico posible, comenta-

remos cómo trabajamos y

qué herramientas usamos.

� Unión de MXML conRailsSe tratará la unión del len-

guaje MXML usado por la

plataforma Flex con el fra-

mework Rails para conse-

guir una aplicación de las

que Adobe denomina RIA.

REDES(ror) 21/9/07 14:26 Página 63