You are on page 1of 45

Cuatro Dias

con Rails

compilado por John McCreesh


traducción por Emmanuel N. Millán
Tabla de Contenidos
Introducción ...................................................................................................................................................1
Día 1 con Rails ...............................................................................................................................................3
La aplicación ‘Lista de Tareas’ .............................................................................................................3
Ejecutar el script de Rails ......................................................................................................................3
Agregar la aplicación al servidor Web ...............................................................................................3
Definir la aplicación en el archivo de hosts ...............................................................................3
Definir la aplicación en el archivo de configuración de Apache .........................................3
Cambiar a fastcgi ................................................................................................................................4
Chequear que Rails este funcionan d o ..........................................................................................4
Versiones de Rails ..............................................................................................................................4
Configurar la Base de Datos .................................................................................................................4
Crear la tabla Categorias ..................................................................................................................5
Definición MySQL..........................................................................................................................5
Modelo de Datos ............................................................................................................................5
Scaffold .......................................................................................................................................................5
Realzar el Modelo .....................................................................................................................................6
Crear reglas de validación de datos ..............................................................................................7
Dia 2 con Rails ...............................................................................................................................................9
El código generado Scaffold .................................................................................................................9
El controlador ......................................................................................................................................9
La Vista ................................................................................................................................................1 1
Layout .............................................................................................................................................11
Template (plantilla) ....................................................................................................................12
Partial (parcial) .............................................................................................................................12
La vista de renderiza do para la acción “New” ....................................................................13
Analizando la vista de la acción ‘List’...................................................................................14
Modificar el código generado por Scaffold ...................................................................................16
El controlador ....................................................................................................................................16
La Vista (View)...................................................................................................................................16
Mostrar mensajes Flash .............................................................................................................16
Compartir variables entre la plantilla y el Layout ............................................................17
Atando las pantallas de Edit y New .......................................................................................18
Día 3 con Rails ............................................................................................................................................19
La tabla ‘Items’ .......................................................................................................................................19
Definición MySQL de la tabla ........................................................................................................19
El Modelo .............................................................................................................................................19
Validar los links entre las tablas ............................................................................................20
Validar la entrada del usuario .................................................................................................20
La tabla de ‘Notas’.................................................................................................................................20
Definición de la tabla MySQL........................................................................................................20
El modelo ............................................................................................................................................21
Usar un Modelo para mantener Integridad Referencial ..................................................21
Mas de Scaffold ......................................................................................................................................22
Mas acerca de Vistas .............................................................................................................................22
Crear un Layout para la Aplicación ............................................................................................22
La pantalla ‘Lista de tareas’ ...........................................................................................................23
Eliminar ‘tareas’ completadas haciendo click en un ícono ............................................24
Cambiar el modo de ordena mien t o haciendo click en el Encabezado de la
Columna .........................................................................................................................................24
Agregar el Helper ........................................................................................................................25
Usar botónes de navegación Javascript ................................................................................25
Formatear una Tabla con un Parcial ......................................................................................25
Formato basado en el valor de los Datos ............................................................................27
Manejar valores perdidos en una busqued a ......................................................................27
La pantalla ‘Nueva Tarea’...............................................................................................................27
Crear una lista desplegable para el campo fecha ..............................................................28
Atrapar excepciones con Ruby ................................................................................................28
Crear una lista desplegable desde una tabla de busqueda ............................................29
Crear una lista desplegable para la lista de constant es ..................................................29
Crear una casilla de verificación ............................................................................................29
Toques finales ........................................................................................................................................29
Modificar la hoja de estilos ...........................................................................................................29
La pantalla ‘Editar Tarea’...............................................................................................................30
Dia 4 con Rails ............................................................................................................................................31
Las pantallas ‘Notas’.............................................................................................................................31
Enlazand o ‘Notas’ con ‘Editar Tarea’..........................................................................................31
La pantalla ‘Editar Notas’ ...............................................................................................................32
La pantalla de ‘Nota Nueva’...........................................................................................................33
Guardar y traer Datos usando variables de Sesión ...........................................................33
Cambiar la pantalla de ‘Categorias’ .................................................................................................34
Navegación a traves del sistema .......................................................................................................34
Descargar una copia de esta aplicación ..........................................................................................35
Y finalmente ............................................................................................................................................35
Apéndice – Cambios posteriores ..........................................................................................................37
Actualizaciones Multiples ...................................................................................................................37
View......................................................................................................................................................37
Controlador ........................................................................................................................................38
Consideraciones de la interfaz de usuario ...............................................................................39
Todavía para hacer ................................................................................................................................39
Introducción

Han habido varias deman da s extravagantes hechas acerca de Rails. Por ejemplo, un
articulo publicado en OnLAMP.com 1 deman da n d o que “puedes desarrollar una aplicación
web por lo menos diez veces mas rápido con Rails que con un tipico framework Java...” El
artículo luego muestra como instalar Rails y Ruby en una PC y contruir una aplicación
funcionan d o con “scaffold” virtualmen te sin código.

Mientras que esto es impresiona nt e, desarrolladores web “reales” saben que esto es humo
y espejos. aplicaciónes ‘reales’ no son tan simples como eso. ¿Qué es realmen te lo que
esta pasan do debajo de la superficie? ¿Qué tan dificil es construir aplicaciónes web
‘reales’?

Aqui es donde la vida se vuelve un poco difícil. Rails tiene muy buena documen t ación
on - line, de hecho, posiblement e esta demasiado bien docume n t a d o para principiantes,
con mas de 30.000 palabras de docume n t ación on- line en el formato de manual de
referencia. Lo que esta faltando en un road ma p (railmap?? - mapa del camino) apunta n d o
a las páginas claves que necesitas saber para comen za r a desarrollar con Rails.

Este documen t o está para llenar ese vacio. Asume que ya tienes Ruby y Rails en
funciona mient o en una PC (si no has llegado tan lejos, ve devuelta y sigue el articulo de
Curt). Esto te lleva al final de ‘Dia 1 con Rails’.

‘Dia 2 con Rails’ comienza posicionan d o se detras del humo y los espejos. Lo lleva a traves
del código ‘scaffold’. Nuevas características son remarcadas en negrita, explicadas en el
texto, y seguidas por una referencia a la documen t acio de Rails o de Ruby donde puedes
aprender más.

‘Dia 3 con Rails’ toma scaffold y comien za a construir algo reconocible como una
aplicación “real”. Todo el tiempo, esta contruyen d o su propia caja de herra mient as con
Rails. Lo mas importa nt e de todo, deberia también sentirse comodo con la
documen t ación en linea para que pueda continuar con la exploración usted solo.

‘Dia 4 con Rails’ agrega otra tabla y trata con algunas de las complejidades de mantene r
la integridad referencial. Al final, tendra una aplicación en funciona mient o, suficientes
herra mient as como para comenza r, y el conocimient o de donde buscar mas información.

Diez veces mas rápido? Después de cuatro dias con Rails, juzguelo por usted mismo!

Documentación : este documen t o contiene referencias destacadas, a cualquiera de los


siguientes sitios:

• Docu m e nt ación – La d oc u m e n t ació n d e Rails en h t t p: / / a pi.r u byo n rails.co m (Esta


d oc u m e n t ació n t a m bié n est a inst ala d a en s u PC co m o p a r te d e la ins talación d e ge m s
u bica d a en u n lugar co m o C:\Program Files\ruby\lib\ruby\gems\n.n\doc\actionpack-
n.n.n\rdoc\index.html)
• Rub y Docu m e n t ación – “Progra m mi ng Ruby - The Prag m a tic Progra m m e r's Guide”
dis p o nible en linea y p a ra bajar en h t t p: / / www.ru by - d oc.org / d ocs / r u by - d oc -
b u n dle /Progra m mi ngRuby /i n d ex.ht ml

1 Rolling with Ruby on Rails, Curt Hibbs 20- Jan2005


http: / / w ww.onla m p.co m / p u b / a / o n l a m p / 2 0 0 5 / 0 1 / 2 0 / r a ils.ht m l

Página 1
Reconocimiento s : m u c h as gracias a la ge n te en el canal irc 2 y e n la lista d e correo 3 . El
regist ro d e arc hivos e n linea fue u n a invaluable asiste ncia m ie n t ras a p re n dia Rails y
Ruby.

Versión: 2.3 usand o la versión 0.12.1 de Rails – vea http: / / r ails.ho melin ux.org para la
última versión y para bajar una copia del futuro código. Document o escrito y pdf
generado con OpenOffice.org 'Writer'.

Copyright : este trabajo tiene copyright ©2005 John McCreesh


jpmcc@users.sourceforge.net y esta bajo la licencia Creative Com mo ns Attribution -
NonCo m m e rcial - ShareAlike License . Para ver una copia de esta licencia, visite
http: / / c re a tiveco m m o n s.org / licenses / b y - nc- sa/2.0 / o envie una carta a Creative
Commo ns, 559 Nathan Abbott Way, Stanford, California 94305, USA.

2 irc:/ /i rc.freeno de.org / r u byon rails


3 http: / / li s t s.rubyonrails.org / m a il m a n / li s tinfo / r ails

Página 2
Día 1 con Rails
La aplicación ‘Lista de Tareas’
Este d oc u m e n t o sig ue la co n s t r ucción d e u n a si m ple a plicació n d e “lista d e ta reas” – el
ti p o d e cosa q ue tienes e n t u PDA, co n u n a lista d e ite m s, agr u p a d o s e n categorias, con
n o ta s o pcio nales (para ver u n a a delan t o d e co m o se va a ver, vea Ilustración 5: La p a nt alla
de ‘Lista de T areas’ en la p ági na 2 3 ).

Ejecutar el script de Rails


Este ejemplo esta en mi PC MS- Windows. Mi material de web esta en c:\www\webroot, que
etiqueto como mi disco w: para acortar el tipeo:

C:\> subst w: c:\www\webroot


C:\> w:
W:\> rails ToDo
W:\> cd ToDo
W:\ToDo>

Ejecutar rails ToDo crea un nuevo directorio ToDo\ y lo puebla con una serie de archivos y
subdirectorios, los mas importan t es de estos son los siguientes:

app
contiene el nucleo de la aplicación, dividida en los subdirectorios modelos (model),
vistas(view), controladores(controller), y 'ayudantes'(helper)
config
contiene el archivo database.yml que provee detalles de la base de datos a utilizar
con la aplicación
log
registros especificos de la aplicación. Nota: development.log mantiene una traza de
cada acción que Rails realiza – muy util para rastrear errores, pero no necesita
ser purgado regularmente!
public
el directorio disponible para Apache, que incluye imagenes, javascripts, y
subdirectorios para stylesheets

Agregar la aplicación al servidor Web


Como yo estoy ejecutand o todo (Apache2, MySQL, etc) en una sola PC de desarrollo, los
siguientes dos pasos dan un nombre amigable para la aplicación en mi navegador.

Definir la aplicación en el archivo de hosts


C:\winnt\system32\drivers\etc\hosts (fragmento)
127.0.0.1 todo

Definir la aplicación en el archivo de configuración de Apache


Apache2\conf\httpd.conf
<VirtualHost *>
ServerName todo
DocumentRoot /www/webroot/ToDo/public
<Directory /www/webroot/ToDo/public/>
Options ExecCGI FollowSymLinks
AllowOverride all
Allow from all
Order allow,deny
</Directory>
</VirtualHost>

Página 3
Cambiar a fastcgi
A menos que sea paciente (o que tenga una PC potente) deberia habilitar fastcgi para esta
aplicación.
public\.htaccess
# Para mejor desempeño reemplaze el despachador con el de fastcgi
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

Chequear que Rails este funcionando


El sitio ahora deberia ser visible en su navegador como http://todo/ (debería ver la página
Congratulations, you've put Ruby on Rails! en su navegador).

Versiones de Rails
Para el m o m e n t o q ue leas este d oc u m e n t o, Rails p r o b able me n te h aya ava n z a d o varias
versió nes. Si inte n t as avan za r a t raves d e este d oc u m e n t o, cheq uea la versión ins tala da en
t u PC:
W:\ToDo>gem list --local

Si s o n dis tin ta s a las versió ne s lista da s abajo, e n t o nces yo fue rte m e n te aco n sejaria q u e
baje las versió nes u s a d a s en “Cuat ro dias co n Rails”, eje m plo:
W:\ToDo>gem install rails --versión 0.12.1

Esto n o ro m p e ra n a d a; la libreria ge m s d e Ruby es ta di se ña d a p a ra m a neja r m ul ti ples


versió nes. Ento nces p ue de for z a r a Rails a q u e u se las versió nes u tili za d a s e n “Cuat ro
Dias” en la a plicación ‘Lista d e Tareas’ es pecifican d o:
config\environment.rb (fragmento)
# Require Rails libraries.
require 'rubygems'
require_gem 'activesupport', '= 1.0.4'
require_gem 'activerecord', '= 1.10.1'
require_gem 'actionpack', '= 1.8.1'
require_gem 'actionmailer', '= 0.9.1'
require_gem 'actionwebservice', '= 0.7.1'
require_gem 'rails', '= 0.12.1'

La ra z ó n p a ra u sa r la m i s m a versió n es m uy si m ple. ‘Cuat ro Dias’ u s a m uc h o có digo


genera d o a u t o m a tica me n te p o r Rails. Mient ras Rails se d e sa r rolla, t a m bié n lo h ace es te
có digo – d e safo rt u n a d a m e n t e, es te d oc u m e n t o n o lo h ace (hasta q ue se p r o d uce u n a
n u eva versió n!). Ento nces, h a s t u vida fácil, y m a n t e ne la m i s m a versió n q u e se u sa e n
‘Cuat ro Dias’. Una ve z q ue h ayas t er mi na d o d e t rabajar co n ‘Cuatro Dias’, ve a la úl ti ma y
gra n versió n d e Rails y ve q ue m ejo ra s los d e sa rr ollad o res d e Rails h a n reali za d o.

Configurar la Base de Datos


He configurad o una nueva base de datos llamada ‘todos’ en MySQL. La conexión a la base
de datos es especificada en el archivo config\database.yml

config\database.yml (fragmento)
development:
adapter: mysql
database: todos
host: localhost
username: foo
password: bar

Página 4
Crear la tabla Categorias
La tabla categories (categorias) es utilizada en los ejemplos siguientes. Es una simple lista
de categorias que seran usadas para agrupar los items en la Lista de Tareas.

Definición MySQL
Tabla Categories
CREATE TABLE `categories` (
`id` smallint(5) unsigned NOT NULL auto_increment,
`category` varchar(20) NOT NULL default '',
`created_on` timestamp(14) NOT NULL,
`updated_on` timestamp(14) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `category_key` (`category`)
) TYPE=MyISAM COMMENT='List of categories';

Algunos tips para los nombres de las tablas y campos:

• Guiones bajos en el nombre de los campos seran cambiados por espacios por Rails
para obtener nombres ‘amigables al humano’
• tener cuidado con la mezcla de mayusculas y minisculas en el nombre del campo –
algunas partes del código de Rails son sensibles a mayusculas y minisculas.
• Cada tabla deberia tener una clave primaria llamada ‘id ’ - en MySQL es mas fácil tener
este campo como un numeric auto_increment
• enlaces a otras tablas deberian seguir la misma convencion de nombre ‘_id’
• Rails auto matica men t e manten d r a los campos llamados created_at/created_on o
updated_at/updated_on, entonces es una buena idea agregarlos
Document ación: ActiveRecord::Timesta m p
• Tip útil: si esta construyen d o un sistema multiusuario (no es relevante aqui), Rails
también utilizara el bloqueo optimista si agrega un campo llamado lock_versión
(integer default 0). Todo lo que necesita recordar es incluir lock_versión como un
campo oculto en sus formularios de actualización.
Document ación: ActiveRecord::Locking

Modelo de Datos
Genera un archivo vacio:

W:\ToDo>ruby script/generate model category


exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/category.rb
create test/unit/category_test.rb
create test/fixtures/categories.yml

W:\ToDo>
q ue crea u n archivo category.rb, y d o s arc hivos d e p r u eba category_controller_test.rb y
categories.yml. Agregare m o s algu na s en t ra d a s e n el m o d elo d e d a t o s e n u n mi n u t o –
d ejelo vacio p o r el m o m e n t o.

Scaffold
El controlador es el corazón de la aplicación Rails.
Ejecutar el script generador del controlador
W:\ToDo>ruby script/generate controller category
exists app/controllers/

Página 5
exists app/helpers/
create app/views/category
exists test/functional/
create app/controllers/category_controller.rb
create test/functional/category_controller_test.rb
create app/helpers/category_helper.rb

W:\ToDo>

que crea dos archivos y dos directorios vacios:


app\controllers\category_controller.rb
app\helpers\category_helper.rb
app\views\categories
app\views\layouts

Si no ha visto el truco modelo / scaffold en funciona mient o en un tutorial de principiante


como “Rolling with Ruby on Rails”, pruebelo ahora y asombrese de como toda una
aplicación web puede estar escrita en una sola linea de código:
app\controllers\category_controller.rb
class CategoryController < ApplicationController
scaffold :category
end
Document ación: ActionController::Scaffolding

Ap u n te s u n avega d o r a http://todo/category y a d mi re q ue t a n ingenioso es : - )

Ilustración 1 : pantalla 'Lista' Scaffold

Para averigüar q u e ta n inge nioso n o es, inte n te agregar la m i s m a categoria d o s veces.


Rails fracasa rá y d a ra u n s ucio m e n saje d e erro r ‘ActiveRecor d::State me n tInvalid in
Category#create’. Pue de ar reglar est o agrega n d o validació n al Modelo.

Realzar el Modelo
El Modelo es donde toda las reglas relacionadas con datos son guarda das, incluida la
validación y integridad relacional. Esto significa que puede definir una sola regla, y Rails
automáticame n t e la aplicará donde sea que el dato es accedido.

Página 6
Crear reglas de validación de datos
Rails otorga mucho manejo de errores gratis (casi). Para demost rar esto, agregue algunas
reglas de validación al modelo de categoría vacio:
app\models\category.rb
class Category < ActiveRecord::Base
validates_length_of :category, :within => 1..20
validates_uniqueness_of :category, :message => "already exists"
end

Estas entradas automa tica men t e chequearan que:

• validates_length_of: el ca m p o n o este en vacio y n o sea m uy largo


• validates_uniqueness_of: valores d u plica d os so n at ra p a d o s. No m e gu s t a
el m e n s aje d e
erro r p o r d efecto d e Rails - ‘xxx has already been taken’ - en t o nces d oy mi p r o pio
m e n s aje. Esta es u n a característica general d e Rails – p ri m e ro p r u ebe los valores p o r
d efecto, si n o le g us t a n, s ob reescribalos.
Document ación: ActiveRecord::Validations::ClassMethods

Página 7
Para p r o ba r es to, a h o ra inte n t a agregar u n regist ro d u plica d o d e n u evo. Esta ve z, Rails
m a n eja el erro r e n ve z d e “ro m p e r se” - vea abajo. El estilo es ta u n p oco en s u cara – n o
es la in terfa z d e u s u a rio m a s s u til. De t o d a s for m a s, q ue es pera si es gratis?

Ilustración 2 : Capturan d o errores de datos

Página 8
Dia 2 con Rails
Para progresar mas alla de este punto, necesita mo s ver que esta pasando detras de la
escena. Durante el dia 2, trabajare m o s sistematica me n t e a traves del código scaffold
generado por Rails, decifrando que significa todo. Con la acción scaffold, Rails genera
todo el código que necesita dinámica me n t e. Ejecutando scaffold como un script , podemo s
obtener todo el código escrito al disco donde lo pode mo s investigar y luego comen za r a
modificarlo para ajustarse a nuestros requeri mient os.
Ejecutar el script generate scaffold
W:\ToDo>ruby script/generate scaffold category
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
skip app/models/category.rb
skip test/unit/category_test.rb
skip test/fixtures/categories.yml
exists app/controllers/
exists app/helpers/
create app/views/categories
exists test/functional/
create app/controllers/categories_controller.rb
create test/functional/categories_controller_test.rb
create app/helpers/categories_helper.rb
create app/views/layouts/categories.rhtml
create public/stylesheets/scaffold.css
create app/views/categories/list.rhtml
create app/views/categories/show.rhtml
create app/views/categories/new.rhtml
create app/views/categories/edit.rhtml
create app/views/categories/_form.rhtml

W:\ToDo>

Este script genera un rango de archivos necesarios para crear una aplicación completa,
incluyendo un controlador, vistas, layouts, e incluso hojas de estilo (css).

Note la p e q u e ña bi za r ra convenció n d e n o m b res – n o s h e m o s m ovi do d el si ng ular a


pl u ral, e n t o nces p a ra u s a r el n u evo có digo n ecesita a p u n t a r el n avega d o r a
http://todo/categories. De hec ho, p a ra evitar co nf u sio ne s, es m ejo r bo rra r
app\controllers\category_controller.rb etc e n caso d e q ue lo ejecute accide n tal me n te.

El código generado Scaffold


El controlador
Vea m o s el có digo d e t ra s d el co n t rola d o r. El co n t rola d o r es d o n d e d e sca n sa la
p r og ra m ació n lógica d e la a plicación. Interact ua con el u s u a rio u sa n d o vistas (views), y
con la base d e d a t o s a t raves d e los m o d elos (mo dels). Deberia p o d e r leer el con t rola d o r y
ver co m o la a plicació n esta u ni da.
El controlador producido por el script generar scaffold es listado abajo:
\app\controllers\categories_controller.rb
class CategoriesController < ApplicationController
def index
list
render_action 'list'
end

def list

Página 9
@category_pages, @categories = paginate :category, :per_page => 10
end

def show
@category = Category.find(@params[:id])
end

def new
@category = Category.new
end

def create
@category = Category.new(@params[:category])
if @category.save
flash['notice'] = 'Category was successfully created.'
redirect_to :action => 'list'
else
render_action 'new'
end
end

def edit
@category = Category.find(@params[:id])
end

def update
@category = Category.find(@params[:id])
if @category.update_attributes(@params[:category])
flash['notice'] = 'Category was successfully updated.'
redirect_to :action => 'show', :id => @category
else
render_action 'edit'
end
end

def destroy
Category.find(@params[:id]).destroy
redirect_to :action => 'list'
end
end

Cuando el usuario de la aplicación Rails selecciona una acción – ejemplo: ‘Show’ (mostrar)
– el controlador ejecutará cualquier código de la sección apropiada – ‘def show’ - y luego
por defecto renderizara una plantilla con el mismo nomb re - ‘show.rthml’. Este
comport a mi en t o por defecto puede ser sobreescrito:

• render_template le permite renderizar una plantilla diferente – ejemplo: la acción index


ejecutara el código de la acción ‘list’ - ‘def list’, y renderizara list.rhtml en vez
de index.rhtml (que no existe)
• redirect_to va un nivel mas alla, y utiliza una respuesta externa HTTP ‘302 moved’
para volver al controlador – ejemplo: la acción destroy no necesita renderizar una
plantilla. Despues de realizar su proposito principal (destruir una categoria),
simpleme n t e lleva al usuario a la acción list.
Document ación: ActionController::Base

El controlador ActiveRecord usa métodos como find (encontrar), find_all (encontrar


todos), new (nuevo), save (guardar), update_attributes (actualizar atributos), y destroy
(destruir) para mover datos a y desde las tablas de la base de datos. Note que no tiene
que escribir ninguna sentencia SQL, pero si desea ver que SQL Rails esta usando, esta
todo escrito en el archivo development.log.

Página 10
Document ación: ActiveRecord::Base

Note co m o u n a activida d lógica d e s d e la p e r s p ectiva d el u s u a rio p ue de req u erir d o s


p a s o s a t raves d el con t r ola do r: p o r eje m plo, act uali za r u n regist r o en la ta bla. Cua n d o el
u s ua rio selecciona ‘Edit’, el con t r ola do r ext rae el regist ro q u e se d e sea e ditar d el m o d elo,
y re n de ri za la vista edit. Cua n d o el u s u a rio finaliz o la e dición, la vista edit invoca la
acció n update, q ue act uali za el m o d elo y luego invoca la acció n show.

La Vista
Las vistas s o n d o n d e se d efine la interfa z d el u s ua rio. Rails p u e d e re n de ri za r la p ági na
HTML fi nal p rese n ta da al u s u a rio d e s de t res co m p o n e n te s:
Layout Template - Plantilla Partial - Parcial
e n app\views\layouts\ e n app\views\<controller>\ e n app\views\<controller>\
p o r d efecto: application.rhtml p o r d efecto: <action>.rhtml p o r d efecto _<partial>.rhtml
o <controller>.rhtml

• Un Layo ut p r ovee có digo co m u n u sa d o p o r t o d a s las acció nes, ti pica me n t e el co mien z o


y final d el HTML envia do al n avega do r.
• Un Te m plate o Plan tilla p rovee el có digo es pecifico a ca da acción, eje m plo có digo d e
‘List’, có digo d e ‘Edit’, etc.
• Un Partial o Parcial p r ovee có digo co m u n - ‘subr u ti nas’ - q u e p ue de se r u s a d o en
m ul ti ples acció nes – eje m plo: có digo u s a d o p a ra m o s t r ar ta blas en u n fo r m ulario.

Layout
Convención de nombres en Rails: si hay una plantilla en app\views\layouts\ con el mismo
nombre que el controlador actual entonces sera utilizada auto máticame n t e como layout
del controlador a menos que explícitamen te se indique lo contrario.

Un layout con el nombre de application.rhtml o application.rxml sera configurado como el


controlado r por defecto si no existe un layout con el mismo nombre que el controlador
actual, y no existe un layout asignado explicitamen t e.

El layout generado por el script scaffold se ve como esto:


app\views\layouts\categories.rhtml
<html>
<head>
<title>Categories: <%= controller.action_name %></title>
<%= stylesheet_link_tag 'scaffold' %>
</head>
<body>

<%= @content_for_layout %>

</body>
</html>

Esto es en su mayoria HTML, mas algunos bits de código Ruby embebido entre etiquetas
<% %>. Este layout sera llamado por el proceso de renderi za d o sin considerar la acción que
se este ejecutan d o. Contiene etiquetas estan da r HTML – las
<html><head>...</head><body>...</body></html> que aparecen en todas las páginas.

Las partes de Ruby en negrita son traducidas a HTML durante el proceso de renderizad o

Página 11
de Rails como se muest ra a continuación:

• es un método ActionController que devuelve el nombre de la acción que el


action_name
controlador esta procesan do (ejemplo ‘List’) - esto coloca el titulo de la página
apropiado, depen dien d o de la acción que se esta ejecutan d o.
Document ación: ActionController::Base

• stylesheet_link_tages un helper (ayudante) de Rails – una manera perezosa de generar


código. Hay muchos de estos ‘ayudantes’ dentro de Rails. Este simplemen te genera el
siguiente código HTML: <link href="/stylesheets/scaffold.css" media="screen"
rel="Stylesheet" type="text/css" />
Document ación: ActionView::Helpers::AssetTagHelper

• es la clave de lo que pasa a continuación. Permite a un unico layout


content_for_layout
estan dar tener contenido dinamico insertado en tiempo de renderizad o basado en la
acción ejecutada (ejemplo ‘edit’, ‘new’, ‘list’). Este contenido dinamico proviene de un
Template (plantilla) con el mismo nombre – ver abajo.
Document ación: ActionController::Layout::ClassMethods.

Template (plantilla)
Convención de nombres de Rails: las plantillas estan guardad as en
app\views\categories\‘acción’.rhtml.

El nuevo .rhtml creado por el script scaffold es mostra do a continuación:


app\views\categories\new.rhtml
<h1>New category</h1>

<%= start_form_tag :action => 'create' %>


<%= render_partial "form" %>
<%= submit_tag "Create" %>
<%= end_form_tag %>

<%= link_to 'Back', :action => 'list' %>

• start_form_tag es un ayudante (helper) de Rails para iniciar un formulario HTML – aqui


genera <form action="/categories/create" method="post">
• submit_tag por si misma generaria <input name="submit" type="submit" value="Save
changes" />, pero el parámet ro “Create” sobreescribe el valor por defecto “Save
changes” con “Create”
• end_form_tag solo imprime </form>, no es el helper de Rails mas útil creado :- ) pero
provee un final satisfactorio para el bloque de código
Document ación: ActionView::Helpers::FormTagHelper

• invocará un Partial (parcial) _form.rhtml – vea la siguiente sección.


render_partial
Document ación: ActionView::Partials

• link_to simplemen te crea un link – la parte mas funda m e n t al de HTML... <a


href="/categories/list">Back</a>
Document ación: ActionView::Helpers::UrlHelper

Partial (parcial)
Convención de nombres de Rails: un parcial ‘foo’ estara en el archivo

Página 12
app\views\‘action’\_foo.rhtml (note el guion bajo inicial).

Scaffol d u sa el mi s m o có digo p a ra p r ocesa r a m b a s ‘edit’ y ‘new’ acció nes, en to nces coloca


el có digo en u n p a rcial, invoca d o p o r el m é t o d o render_partial.
app\views\categories\_form.rhtml
<%= error_messages_for 'category' %>

<!--[form:category]-->
<p><label for="category_category">Category</label><br/>
<%= text_field 'category', 'category' %></p>

<p><label for="category_created_on">Created on</label><br/>


</p>

<p><label for="category_updated_on">Updated on</label><br/>


</p>
<!--[eoform:category]-->

• error_messages_fordevuelve una cadena con marca – texto para cualquier mensaje de


error producido por un intento de enviar el formulario. Si uno o mas errores son
detectados, el HTML se vera asi:
<div class="errorExplanation" id="errorExplanation">
<h2>n errors prohibited this xxx from being saved</h2>
<p>There were problems with the following fields:</p>
<ul>
<li>field_1 error_message_1</li>
<li>... ...</li>
<li>field_n error_message_n</li>
</ul>
</div>

Vimos esto en acción en el Día 1 - Ilustración 2: Capturando errores de datos en la


página 8 . Nota: las etiquetas css igualan las correspo n dien tes declaraciones en la hoja
de estilos creada por el script generar scaffold.
Document ación: ActionView::Helpers::ActiveRecordHelper

• text_field es un helper de Rails que genera este HTML: <input id="category_category"


name="category[category]" size="30" type="text" value="" />. El primer parámet ro es el
nombre de la tabla; el segund o es el nombre del campo.
Document ación: ActionView::Helpers::FormHelper

Note u n p e q ue ñ o b u g e n Rails – sa be co m o n o crear u n ca m p o d e en t ra da p a ra los


ca m p o s re serva d o s create d_o n y u p d a t e d_on , p e ro a u n asi ge ne ra las etiq ue ta s p a ra
ellos.

La vista de renderizado para la acción “New”


Estamos ya en posición de mirar el código que devuelve al navegador en respuesta a la
acción “New”, y ver de donde vino todo. El Layout provee el texto en negrita; la plantilla
(template) el texto regular; y el parcial el texto en Italica :
app\views\categories\new.rhtml
<html>
<head>
<title>Categories: new</title>
<link href="/stylesheets/scaffold.css" media="screen" rel="Stylesheet"
type="text/css" />
</head>

Página 13
<body>

<h1>New category</h1>

<form action="/categories/create" method="post">

<!--[form:category]-->
<p><label for="category_category">Category</label><br/>
<input id="category_category" name="category[category]" size="30" type="text" value=""
/></p>

<p><label for="category_created_on">Created on</label><br/>


</p>

<p><label for="category_updated_on">Updated on</label><br/>


</p>
<!--[eoform:category]-->

<input name="submit" type="submit" value="Create" />


</form>

<a href="/categories/list">Back</a>

</body>
</html>

Analizando la vista de la acción ‘List’


Las vistas ‘Edit’ y ‘Show’ so n si milares a la vista ‘New’. ‘List’ co ntiene algu n o s t r ucos
n u evos. Recuer de co m o el co n t rola d o r ejecut o la siguien te pie z a d e có digo a n t es d e
re n d eri za r la pla n tilla ‘List’:
@category_pages, @categories = paginate :category, :per_page => 10

p agina te p u e bla la variable d e ins ta ncia @categories con regist ro s o r de n a d o s d e la t abla


Categories, :per_page regist ra p o r ve z, y con tie ne t o d a la lógica p a ra la n avegació n a la
p ágina sig uie n te / a n terio r. @category_pages es u n a ins ta ncia a Paginator. Co m o s o n u s a d a s
e n la pla n tilla se ex plican al final d e la sig uien te secció n.
Document ación: ActionController::Pagination

La pla n tilla se ve co m o sigue:


app\views\categories\list.rhtml
<h1>Listing categories</h1>

<table>
<tr>
<% for column in Category.content_columns %>
<th><%= column.human_name %></th>
<% end %>
</tr>

<% for category in @categories %>


<tr>
<% for column in Category.content_columns %>
<td><%=h category.send(column.name) %></td>
<% end %>
<td><%= link_to 'Show', :action => 'show', :id => category %></td>
<td><%= link_to 'Edit', :action => 'edit', :id => category %></td>
<td><%= link_to 'Destroy', {:action => 'destroy', :id => category}, :confirm =>
"Are you sure?" %></td>
</tr>
<% end %>
</table>

Página 14
<%= link_to "Previous page", { :page => @category_pages.current.previous } if
@category_pages.current.previous %>
<%= link_to "Next page", { :page => @category_pages.current.next } if
@category_pages.current.next %>

<br />

<%= link_to 'New category', :action => 'new' %>

• content_columns devuelve un array de objetos columna excluyendo cualquier columna


‘especial’ (la clave primaria id, todas las columnas que finalizen con ‘_id’ o ‘_count’, y
columnas usadas para herencia de tablas)
Document ación: ActionController::Base

• es un sinóni mo de human_attribute_name, que transfor m a nombre de


human_name
atribut os claves en un formato leible para el huma no, como ‘Primer nombre’ en vez de
‘primer_nombre’
Document ación: ActiveRecord::Base

• h automáticame n t e ‘sale’ del código HTML. Uno de los problemas en permitirle al


usuario que ingrese datos que luego son mostrad o s en la pantalla es que pueden
accidental me n t e (o maliciosamen te) ingresar código que podria romper el sistema
cuando es mostra do 4 . Para cuidarse contra esto, es buena practica utilizar ‘escape
HTML’ con cualquier dato que es provisto por el usuario. Esto significa que por
ejemplo </table> es renderiza d o como &lt;/table&gt; que es inofensivo. Rails hace esto
realmente simple – solo agrega una ‘h’ como se muestra.

• confirm es u n p a rá m e t r o o pcio nal m uy ú til p a ra el hel per link_to – genera u n a caja


e me rge n t e d e JavaScri p t q ue f uer z a al u s u a rio a confir ma r la acció n Destroy a n tes d e
ejecu ta r el link:

Ilustración 3 : Javascript emergente

Document ación: ActionView::Helpers::UrlHelper

La lógica d e la p ági na se aclara u n p oco. Ruby p u e de u tili za r if co m o m o difica do r:


expresion if expresion-booleana evalua expresion solo si expresion-boolean es ver da de ra.
@category_pages.current d ev uelve u n object o Página re p re se n t a n d o la p ági na act u al.

ActionController::Pagination::Paginator
y @category_pages.current.previous d ev uelve u n n u evo objeto Página re p rese n t a d o la
p ágina a n terio r a la act ual, o n ulo si esta es la p ri m e ra p ági na.
ActionController::Pagination::Paginator::Page

4 Por ejemplo, piense que pasaria si un usuario tipea “< / t a ble >” como una categoria.

Página 15
Ento nces, si h ay u n a p ágina a n te rior a la cual n avegar, este co nt r uc to r m o s t ra rá u n link;
si n o h ay ni ng u n a, el link es s u p ri mi d o.
El có digo genera d o p a ra la p ágina n se vera asi:
<a href="/categories/list?page=[n-1]">Previous page</a>
<a href="/categories/list?page=[n+1]">Next page</a>

Modificar el código generado por Scaffold


El có digo genera d o p o r el scri p t Scaffold es p e rfecta me n te u sa ble, y es r ob u s t o u n a ve z
q ue h aya agrega d o s uficiente vali dació n al m o d elo d e d a t o s. De t o d a s for m a s, si es to
fuera t o d o el d e sa r rollo n ecesario p a ra a plicació nes Rails, en t o nces los p rogra m a d o res se
q ue da rian si n t rabajo, q u e clara m e n te n o es algo b ue n o : - ) asi q u e reali ze m o s algu n as
m o dificaciones:

El controlador
En la vista ‘List’, esperaria que los registros sean mostrad o s en orden alfabético. Esto
requiere un cambio menor al controlador:
app\controllers\categories_controller.rb (fragmento)
def list
@category_pages, @categories = paginate :category,
:per_page => 10, :order_by => 'category'
end

Document ación: ActionController::Pagination

En esta aplicación, la pantalla show es innecesaria – todos los campos entran


comoda me n t e en una sola linea de la pantalla. Entonces, def show puede desaparecer, y
vayamos directa me n t e a la pantalla list despues de un ‘Edit’:
app\controllers\categories_controller.rb (fragmento)
def update
@category = Category.find(@params[:id])
if @category.update_attributes(@params[:category])
flash['notice'] = 'Category was successfully updated.'
redirect_to :action => 'list'
else
render_action 'edit'
end
end

El mensaje flash será toma do y mostrara en la siguiente pantalla – en este caso, la


pantalla list. Por defecto, el script scaffold no muestra mensajes flash – cambiare mo s
esto en un minuto – vea abajo.

La Vista (View)

Mostrar mensajes Flash


Rails p rovee u n a t écnica p a ra p a sa r m e n sajes flas h al u s ua rio – eje m plo, u n m e n s aje d e
‘Act uali zació n Exitosa’ q u e se m u e s t ra en la sig uien te p a n t alla y luego d e sa pa rece. Esto s
p u e de n ser t o m a d o s fácil me n t e co n u n p e q ue ño ca m bio al Layo ut (agregarlo al Layou t
significa q ue a pa recera n en cualq uier p a n talla):
app\views\layouts\categories.rhtml<html>
<head>
<title>Categories: <%= controller.action_name %></title>
<%= stylesheet_link_tag 'scaffold' %>

Página 16
</head>
<body>
<h1><%=@heading %></h1>
<% if @flash["notice"] %>
<span class="notice">
<%=h @flash["notice"] %>
</span>
<% end %>
<%= @content_for_layout %>
</body>
</html>

Document ación: ActionController::Flash

Un simple agregado a la hoja de estilo hace que el mensaje flash sea mas visible:
public\stylesheets\scaffold.css (fragmento)
.notice {
color: red;
}

Compartir variables entre la plantilla y el Layout


Note que he movido el texto encabeza d o <h1>...</h1> de la plantilla al Layout para que
aparezca sobre el mensaje flash. Como cada plantilla tendra un encabezad o diferente,
necesito colocar el valor de la variable @heading en la plantilla. Rails no tiene problemas
con esto – variables de plantilla estan disponibles para los Layouts en tiempo de
renderiza do.

He realizado este cambio y algunos cambios de formato para terminar mi plantilla:


app\views\categories\list.rhtml
<% @heading = "Categorias" %>
<table>
<tr>
<th>Categoría</th>
<th>Creada</th>
<th>Actualizada</th>
</tr>
<% for category in @categories %>
<tr>
<td><%=h category["category"] %></td>
<td><%= category["created_on"].strftime("%I:%M %p %d-%b-%y") %></td>
<td><%= category["updated_on"].strftime("%I:%M %p %d-%b-%y") %></td>
<td><%= link_to 'Editar', :action => 'edit', :id => category %></td>
<td><%= link_to 'Eliminar', {:action => 'destroy', :id => category},
:confirm => "¿Esta seguro que desea eliminar esta categoria?" %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'Nueva categoría', :action => 'new' %>
<% if @category_pages.page_count>1 %>
<hr />
Page: <%=págination_links @category_pages %>
<hr />
<% end %>

• No me gusta el format o de la fecha por defecto, entonces uso el método strftime() de


Ruby para formatear los campos de fecha y hora a la forma que quiero.
Ruby Document ación: class Time

Página 17
• págination_links crea u n a ba r ra lin k HTML bá sica p a ra u n p agi na d o r d a d o
ActionView::Helpers::PaginationHelper

Atando las pantallas de Edit y New


Un par de cambios al Parcial utilizado por ‘New’ y ‘Edit’: usé una tabla para mejorar el
layout; deshacer me de las innecesarias etiquetas created_on/ updated_on; y prevenir que el
usuario tipee mucho dentro del campo Category:
app\views\categories\_form.rhtml
<%= error_messages_for 'category' %>
<table>
<tr>
<td><b><label for="category_category">Category:</label></b></td>
<td><%= text_field "category", "category", "size"=>20, "maxlength"=>20 %></td>
</tr>
</table>

y algunos cambios menores a las dos plantillas (note en particular el uso de @heading)::
app\views\categories\Edit.rhtml
<% @heading = "Edit Category" %>
<%= start_form_tag :action => 'update', :id => @category %>
<%= render_partial "form" %>
<hr />
<%= submit_tag "Save" %>
<%= end_form_tag %>
<%= link_to 'Back', :action => 'list' %>

app\views\categories\New.rhtml
<% @heading = "New Category" %>
<%= start_form_tag :action => 'create' %>
<%= render_partial "form" %>
<hr />
<%= submit_tag "Save" %>
<%= end_form_tag %>
<%= link_to 'Back', :action => 'list' %>

Esto n o s lleva al final d el Dia 2. Tene m o s u n sis te m a fu ncio na n d o p a ra m a n te ner n u es t ra


t abla d e Categorias, y he m o s e m p e z a d o a t o m a r con t rol d el có digo scaffold q u e Rails h a
genera d o.

Página 18
Día 3 con Rails
Ahora es tiempo de empezar con el corazón de la aplicación. La tabla Items contiene la
lista de “cosas para hacer”. Cada item puede pertenecer a una de las categorias creadas
en el Dia 2. Un item opcionalmen t e puede tener un Nota, guardad a en una tabla separada,
que veremos mañana. Cada tabla tiene una clave primaria ‘id’, que también es usada para
guardar links entre las tablas.

Categories Items Notes


id id id
category_id
note_id

Ilustración 4 : Modelo de datos simplificado

La tabla ‘Items’
Definición MySQL de la tabla
Los ca m p o s en la t abla Ite m s so n los sig uie n tes:
• d o ne – 1 sig nifica q ue el ite m d e la lista ha si d o finali za d o 5
• p rio rity – 1 (Alta p rio ri da d) a 5 (baja p riori da d)
• d e scri p tion – texto libre in dican d o cual es la ta rea
• d u e_da te – in dica cua n d o se d e be ria reali za r la ta rea
• category_id – u n link a la Categoria a la q ue este ite m p e r te nece (‘id’ en la t abla d e
Catego rias)
• n o te_id – u n link a u n a n o ta o pcio nal ex plican d o es te ite m (‘id’ en la ta bla d e n o t as)
• p rivate – 1 sig nifica q ue el ite m d e la lista est a clasifica d o co m o ‘Priva do’

Tabla Items
CREATE TABLE items (
id smallint(5) unsigned NOT NULL auto_increment,
done tinyint(1) unsigned NOT NULL default '0',
priority tinyint(1) unsigned NOT NULL default '3',
description varchar(40) NOT NULL default '',
due_date date default NULL,
category_id smallint(5) unsigned NOT NULL default '0',
note_id smallint(5) unsigned default NULL,
private tinyint(3) unsigned NOT NULL default '0',
created_on timestamp(14) NOT NULL,
updated_on timestamp(14) NOT NULL,
PRIMARY KEY (id)
) TYPE=MyISAM COMMENT='List of items to be done';

El Modelo
Co m o a n tes, Rails p u e de genera r u n arc hivo d e m o d elo vacio:
W:\ToDo>ruby script/generate model item
exists app/models/
exists test/unit/
exists test/fixtures/

5 MySQL no tiene un tipo ‘booleano’, entonces usamos 0/1

Página 19
create app/models/item.rb
create test/unit/item_test.rb
create test/fixtures/items.yml

W:\ToDo>
q ue p o d e m o s p o blar co n:
app\models\item.rb
class Item < ActiveRecord::Base
belongs_to :category
validates_associated :category
validates_format_of :done_before_type_cast, :with => /[01]/, :message=>"must be 0 or
1"
validates_inclusion_of :priority, :in=>1..5, :message=>"must be between 1 (high) and
5 (low)"
validates_presence_of :description
validates_length_of :description, :maximum=>40
validates_format_of :private_before_type_cast, :with => /[01]/, :message=>"must be 0
or 1"
end

Validar los links entre las tablas


• El uso de belongs_to (pertenece a) y validates_associated (validar asociaciones) enlaza
la tabla Items con el campo item_id de la tabla Category.
Document ación: ActiveRecord::Associations::ClassMethods

Validar la entrada del usuario


• validates_presence_of proteje los campos ‘NOT NULL’ contra entradas nulas del
usuario
• validates_format_of usa expresiones regulares para chequear el formato de la entrada
del usuario
• cuando un usuario tipea una entrada para un campo numérico, Rails siempre la
convertira a un número – si todo falla, un cero. Si desea chequear que el usuario ha
realmente tipeado un número, entonces necesita validar la entrada con
_before_type_cast, que permite acceder la entrada ‘bruta’ 6 .
• validates_inclusion_of chequea la entrada del usuario contra un rango de valores
permitidos
• validates_length_of previene que el usuario ingrese datos que serian truncados cuando
se almacenen 7 .
Document ación: ActiveRecord::Validations::ClassMethods

La tabla de ‘Notas’
Esta t a bla co n tiene u n solo ca m p o d e t ext o libre p a ra con te ner infor m ación f ut u r a p a ra
u n ite m d e la lista d e t a reas en p a r ticular. Este d a t o p o d ria, p o r s u p u es t o, h a ber si d o
con te ni d o en u n ca m p o d e la t abla Ite m s, d e t o d a s for m a s, si lo h ace d e es ta for m a
a p re n d e ra m u c h o m a s acerca d e Rails : - )

Definición de la tabla MySQL


Tabla Notes
CREATE TABLE notes (

6 Lo que pareceria una alternativa mucho mas obvia: validates_inclusion_of


:done_before_type_cast, :in=>"0".."1", :message=>"must be between 0 and 1" – falla si el
campo de entrada queda en blanco
7 Puede combinar las dos reglas para el campo de Descripción en una sola: validates_length_of
:description, :within => 1..40

Página 20
id smallint(6) NOT NULL auto_increment,
more_notes text NOT NULL,
created_on timestamp(14) NOT NULL,
updated_on timestamp(14) NOT NULL,
PRIMARY KEY (id)
) TYPE=MyISAM COMMENT='Additional optional information for to-dos';

El modelo
Genere el archivo de modelos vacio, pero no contiene nada nuevo:
app\models\note.rb
class Note < ActiveRecord::Base
validates_presence_of :more_notes
end

p e r o n ecesita m o s recor d a r agregar este enlace al m o d elo d e Items :


app\models\item.rb (fragmento)
class Item < ActiveRecord::Base
belongs_to :note

Usar un Modelo para mantener Integridad Referencial


El có digo q ue esta m o s a p u n t o d e d e sar r ollar p e r mitira al u s u a rio agregar u n a n o t a a
cualq uier Ite m. Pero q u e ocu rre cua n d o u n u s u a rio bo r ra u n Ite m q ue tiene u n n o t a
asocia da? Clara me n t e, n ecesita m o s e nco n t ra r u n a for m a d e bo rra r el regist ro d e la Nota
t a m bié n, d e o t ra fo r m a n o s q u e d a n regist ro s Notas “huerfa n o s”.
En la for m a d e reali za r el t rabajo Modelo / Vista / Con t r ola do r, es te có digo p e r te nece al
m o d elo. ¿Porq ué? Bien, p o d r a ver m a s ta r de q u e p o d e m o s bo r ra r regist ro s Ite m s
h acien d o click e n u n íco no d e p a p elera d e reciclaje en la p a n talla “lista d e t a reas”, p e r o
t a m bié n p o de m o s b o r ra r u n ite m h acien d o click en Purgar ite m s co m pleta d o s. Colocan d o
el có digo en el Modelo, sera ejecu ta d o sin te ne r en cue n t a d e d o n d e p rove nga la acción d e
eli mi na r.
app\models\item.rb (fragmento)
def before_destroy
unless note_id.nil?
Note.find(note_id).destroy
end
end

Esto se lee: antes de borrar un registro Item, encontrar el registro en Notas cuyo id sea
igual al valor de Nota_id en el registro Item que se esta a punto de eliminar, y eliminarlo
primero. A menos que no exista uno :- )

Similarmen te, si un registro es eliminado de la tabla Notas, entonces cualquier referencia


a este en la tabla Items necesita ser eliminada:
app\models\note.rb (fragmento)
def before_destroy
Item.find_by_note_id(id).update_attribute('note_id',NIL)
end
end

Document ación: ActiveRecord::Callbacks

Página 21
Mas de Scaffold
Generemo s algo mas de código scaffold. Haremos esto para la tabla Items y la tabla
Notas. Todavía no estamos listos para trabajar sobre Notas, pero tener en su lugar a
scaffold significa que podemo s referirnos hoy al código de las Notas sin generar muchos
errores. Es como construir una casa – scaffold permite contruir una pared a la vez sin
que todo se derru m be alrededor de sus ojos.

W:\ToDo>ruby script/generate scaffold Item


[snip]
W:\ToDo>ruby script/generate scaffold Note
[snip]
W:\ToDo>

Nota: co m o m o difica m o s la h oja d e estilos ayer, ingrese “n” a la p reg u n t a “overwrite


(sobreescribir) p u blic / s tyles heet s / scaffol d.css? [Ynaq]”.

Mas acerca de Vistas


Crear un Layout para la Aplicación
Para a ho ra, se esta volvien d o o bvio d e q u e t o d a s m i s pla n tillas te n d ra n las m i s m a s
p ri m era s lineas d e có digo, e n t o nces tiene se n ti do m over el có digo e n co m u n a u n layou t
d e la a plicació n. Borre t o d o s los arc hivos app\views\layouts\*.rhtml, y ree m placelos p o r
u n arc hivo co m ú n application.rhtml.
app\views\layouts\application.rhtml
<html>
<head>
<title><%= @heading %></title>
<%= stylesheet_link_tag 'todo' %>
<script language="JavaScript">
<!-- Begin
function setFocus() {
if (document.forms.length > 0) {
var field = document.forms[0];
for (i = 0; i < field.length; i++) {
if ((field.elements[i].type == "text") || (field.elements[i].type == "textarea")
|| (field.elements[i].type.toString().charAt(0) == "s")) {
document.forms[0].elements[i].focus();
break;
}
}
}
}
// End -->
</script>
</head>
<body OnLoad="setFocus()">
<h1><%=@heading %></h1>
<% if @flash["notice"] %>
<span class="notice">
<%=h @flash["notice"] %>
</span>
<% end %>
<%= @content_for_layout %>
</body>
</html>

El @heading en la plantilla es ahora utilizado para las etiquetas <title> como también para
<h1>. He renom bra d o public/stylesheets/scaffold.css a todo.css para mantener una
prolijidad, y también he jugado general ment e con los colores, bordes de las tablas, para

Página 22
dar un estilo mas lindo. También he agregado un poco de Javascript para
automáticame n t e posicionar el cursor en el primer campo de entrada en el navegador
para que el usuario comienze a tipear.

La pantalla ‘Lista de tareas’


Lo q ue est oy inte n t a d o co n seg uir es u n a vista ba sa da e n u n escrit orio Pal mPilot o PDA
si milar. El p r o d uct o fi nal es m o s t ra d o en la Ilus t ració n 5: La p a n t alla d e ‘Lista d e Tareas’8 .
Algu n o s p u n t o s:
• h acien d o click en el e ncabe za d o d e la col u m n a ‘tilde’ (√) eli mi nara t o d o s los ite m s
co m pleta d o s. (aq uellos m a rca d o s con u n a til de)
• La p a n t alla p u e de ser o r de n a d a hacien d o click e n los encabe z a d o s d e las col u m n a s
‘Pri’, ‘Descri pción’, ‘Finali za r’, y ‘Categoria’
• los valores 0 / 1 p a ra ‘Ter mi na d o’ s o n co nverti d os en p e q u e ñ o s ícon os til des
• ite m s q u e p a sa ro n la fecha d e finali zació n (due d a t e) s o n colorea d o s en rojo y
m o s t ra d o s e n n egrita
• la p re se ncia d e u n a n o t a asociad a es m o s t ra d a co n el ícon o ‘nota’
• los valores 0 / 1 p a ra ‘Priva do’ so n conver ti do s en u n sí m bolo d e can d a d o
• ite m s in divid uales p u e de n ser e di ta d o s o eli mi na d o s h acien d o click en los ícono s d e la
d e recha d e la p a n t alla
• la p a n t alla tiene u n lin do efecto d e ‘franjas’
• n u evos ite m s p ue de n se r agrega d o s h acien d o click en el b o t ó n ‘Nueva Tarea...’ e n la
p a r te inferior d e la p a n t alla
• h ay u n bo t ó n e nlace a las ‘Categorias’ d el Día 2

Ilustración 5 : La pantalla de ‘Lista de Tareas’

La pla n tilla u tili za d a p a ra o b te ne r est o es la sig uien te:

8 Es asombros o lo que un par de lineas en la hoja de estilos pueden hacer para cambiar la
apariencia de la pantalla, por supues to ademas de la colección de íconos...

Página 23
app\views\items\list.rhtml
<% @heading = "To Do List" %>
<%= start_form_tag :action => 'new' %>
<table>
<tr>
<th><%= link_to_image "done", {:action => "purge_completed"}, :confirm => "Are you
sure you want to permanently delete all completed To Dos?" %></th>
<th><%= link_to_image "priority",{:action => "list_by_priority"}, "alt" => "Sort
by Priority" %></th>
<th><%= link_to_image "description",{:action => "list_by_description"}, "alt" =>
"Sort by Description" %></th>
<th><%= link_to_image "due_date", {:action => "list"}, "alt" => "Sort by Due Date"
%></th>
<th><%= link_to_image "category", {:action => "list_by_category"}, "alt" => "Sort
by Category" %></th>
<th><%= show_image "note" %></th>
<th><%= show_image "private" %></th>
<th>&nbsp;</th>
<th>&nbsp;</th>
</tr>
<%= render_collection_of_partials "list_stripes", @items %>
</table>
<hr />
<%= submit_tag "New To Do..." %>
<%= submit_tag "Categories...", {:type => 'button', :onClick=>"parent.location='" +
url_for( :controller => 'categories', :action => 'list' ) + "'" } %>
<%= end_form_tag %>
<%= "Page: " + pagination_links(@item_pages, :params => { :action => @params["action"]
|| "index" }) + "<hr />" if @item_pages.page_count>1 %>

Eliminar ‘tareas’ completadas haciendo click en un ícono


Imagenes clickeables so n crea da s p o r link_to_image, q ue p o r d efecto es pe ra enco n t rar la
i mage n en pub/images con u n a exte n sió n .png; h acien d o click en la i mage n ejecu ta ra u n
m é t o d o es pecífico.
Agrega n d o el p a rá m e t ro :confirm genera u n a ven ta n a d e dialogo e me rge n te javascri p t
co m o a n te s
Document ación: ActionView::Helpers::UrlHelper

Haciendo click en ‘OK’ ejecuta el método purge_completed. Este nuevo método


purge_completed necesita ser definido en el controlado r:
app\controllers\items_controller.rb (fragmento)
def purge_completed
Item.destroy_all "done = 1"
redirect_to :action => 'list'
end

Item.destroy_all eli mi na t o d o s los regist ro s d e la t abla Items d o n d e el valor d el ca m p o id


done es 1, y luego d evuelve la acción list.

Document ación: ActiveRecord::Base

Cambiar el modo de ordenamiento haciendo click en el Encabezado de la Columna


Clickeando en el ícono de Pri invoca el método list_by_priority. Este nuevo método
list_by_priority necesita ser defenido en el controlador:
app\controllers\items_controller.rb (fragmento)
def list
@item_pages, @items = paginate :item,
:per_page => 10, :order_by => 'due_date,priority'

Página 24
end

def list_by_priority
@item_pages, @items = paginate :item,
:per_page => 10, :order_by => 'priority,due_date'
render_action 'list'
end

Especificamos un modo de ordena mien to por defecto en el método list , y creamos un


nuevo método list_by_priority 9 . Note también que necesita mo s explicitame n te
render_action 'list', por defecto Rails intentará renderizar una plantilla llamada
list_by_priority (que no existe :- )

Agregar el Helper
Los encabezad o s para las columnas Nota y Privado son imagenes, pero no son
clickeables. He decidido escribir un pequeño método show_image(name) para solo most rar
la imagen:
app\helpers\application_helper.rb
module ApplicationHelper
def self.append_features(controller)
controller.ancestors.include?(ActionController::Base) ?
controller.add_template_helper(self) : super
end

def show_image(src)
img_options = { "src" => src.include?("/") ? src : "/images/#{src}" }
img_options["src"] = img_options["src"] + ".png" unless
img_options["src"].include?(".")
img_options["border"] = "0"
tag("img", img_options)
end
end

Una vez que el helper ha sido enlaza do por el controlado r:


app\controllers\application.rb
class ApplicationController < ActionController::Base
helper :Application
end
esta disponible para todas las plantillas en la aplicación
Document ación: ActionView::Helpers

Usar botónes de navegación Javascript


onClick es u n a técnica s ta n d a r d Javascri pt p a ra m a nejar acció nes d e bo tó ne s co m o
n avegar a u n a n u eva p ági na. De t o d a s for m a s, Rails reescribe las di reccio nes URLs,
e n t o nces n ecesita m o s p reg u n t a rle a Rails p o r la di reccio n URL cor recta a u tili za r. Dad o
u n controlador y u n a acción, url_for devolverá la URL.
Document ación: ActionController::Base

Formatear una Tabla con un Parcial


Queria crear un efecto de franjas para la lista de items. Los Parciales (Partial) proveen la
solución; pueden ser invocados por el método render_partial:

<% for item in @items %>

9 list_by_description y list_by_category son similares y son dejados como un fácil ejercicio


para el lector. De todas formas, si queda trabado con list_by_category, vea en la página 39

Página 25
<%= render_partial "list_stripes", item %>
<% end %>

o por el mas económico método render_collection_of_partials:


render_collection_of_partials "list_stripes", @items
Document ación: ActionView::Partials

Rails también pasa un número secuencial list_stripes_counter al Parcial. Esta es la clave


para el formato alternad o de las filas en la tabla con o un fondo gris claro o un fondo gris
oscuro. Una forma simple para probar si el contador es impar o par: si es impar, usar el
gris claro, si es par, usar el gris oscuro.

El Parcial completo es como sigue:


app\views\items\_list_stripes.rhtml
<tr class="<%= list_stripes_counter.modulo(2).nonzero? ? "dk_gray" : "lt_gray" %>">
<td style="text-align: center"><%= list_stripes["done"] == 1 ?
show_image("done_ico.gif") : "&nbsp;" %></td>
<td style="text-align: center"><%= list_stripes["priority"] %></td>
<td><%=h list_stripes["description"] %></td>
<% if list_stripes["due_date"].nil? %>
<td>&nbsp;</td>
<% else %>
<%= list_stripes["due_date"] < Date.today ? '<td class="past_due" style="text-
align: center">' : '<td style="text-align: center">' %><%=
list_stripes["due_date"].strftime("%d/%m/%y") %></td>
<% end %>
<td><%=h list_stripes.category ? list_stripes.category["category"] : "Unfiled"
%></td>
<td><%= list_stripes["note_id"].nil? ? "&nbsp;" : show_image("note_ico.gif")
%></td>
<td><%= list_stripes["private"] == 1 ? show_image("private_ico.gif") : "&nbsp;"
%></td>
<td><%= link_to_image("edit", { :controller => 'items', :action => "edit", :id =>
list_stripes.id }) %></td>
<td><%= link_to_image("delete", { :controller => 'items', :action => "destroy",
:id => list_stripes.id }, :confirm => "Are you sure you want to delete this item?")
%></td>
</tr>

Un poco de Ruby es usado para probar si el contador es impar o par y renderizar o


class=“dk_gray” o class=“lt_gray”:
list_stripes_counter.modulo(2).nonzero? ? "dk_gray" : "lt_gray"
el código hasta el signo de iterrogación pregunta: es el resto cuando se divide
list_stripes_counter por 2 es diferente a cero?
Ruby Document ación: class Numeric

El resto de la linea es en realidad una criptica expresión if then else que sacrifica ser
legible por ser breve: if la expresión antes de la marca de pregunta es verdadera,
devuelve el valor antes de los dos puntos; sino devuelve el valor después de los dos puntos.
Ruby Document ación: Expressions

Las dos etiquetas dk_gray y lt_gray son definidas en la hoja de estilos:


public\stylesheets\ToDo.css (fragmento)
.lt_gray { background-color: #e7e7e7; }
.dk_gray { background-color: #d6d7d6; }

Nota: el mismo constructor if then else es usado para mostrar el ícono ‘tilde’ si

Página 26
list_stripes["done"]es igual a 1, de otra forma muestra un caracter de espacio en blanco
HTML:

list_stripes["done"] == 1 ? show_image("done_ico") : "&nbsp;"

Formato basado en el valor de los Datos


Ta m bién es fácil resalta r ite m s es pecíficos d e d a t o s – p o r eje m plo, fecha s en el p a sa d o.
list_stripes["due_date"] < Date.today ? '<td class="past_due">' : '<td>'
De n uevo, est o n ecesita se r igual a la e n t ra d a .past_due en la h oja d e estilos.

Manejar valores perdidos en una busqueda


Quere m o s q ue el sis te m a p ue d a cub ri rse e n la sit uació n d o n d e el u s u a rio bo rra u n a
Categoria q u e est a sie n d o u s a d a p o r u n ite m en la Lista d e Tareas. En este caso, la
Categoria d e be ria ser m o s t ra d a co m o ‘sin arc hivar’:
list_stripes.category ? list_stripes.category["category"] : 'Unfiled'

OK si h a llega d o h a s ta a q ui, d e beria te ner u n a p a n t alla ‘Lista d e Tareas’ q ue se vea algo


co m o la Ilust ración 5 La p a n talla de ‘Lista de T areas’ en la p ágina 2 3 .

La pantalla ‘Nueva Tarea’


Ahora sig ue q u e p a sa cua n d o u n o p re sio na el b ot ó n d e ‘Nueva Tarea...’. De n u evo, t o davía
q ue da n algu n o s t r uco s en el có digo.

Ilustración 6 Pantalla Tarea Nueva

La pla n tilla es m í ni m a:
app\views\items\new.rhtml
<% @heading = "New To Do" %>
<%= error_messages_for 'item' %>
<%= start_form_tag :action => 'create' %>
<table>
<%= render_partial "form" %>
</table>
<hr />
<%= submit_tag "Save" %>
<%= submit_tag "Cancel", {:type => 'button', :onClick=>"parent.location='" + url_for(
:action => 'list' ) + "'" } %>
<%= end_form_tag %>

Página 27
y el t rabajo real es reali za d o en el p a rcial, q u e p u e d e ser co m p a r ti d o con la acción ‘Edit’:
app\views\items\_form.rhtml
<tr>
<td><b>Descripción: </b></td>
<td><%= text_field "item", "description", "size" => 40, "maxlength" => 40
%></td>
</tr>
<tr>
<td><b>Finalizar: </b></td>
<td><%= date_select "item", "due_date", :use_month_numbers => true %></td>
</tr>
<tr>
<td><b>Categoria: </b></td>
<td><select id="item_category_id" name="item[category_id]">
<%= options_from_collection_for_select @categories, "id", "category",
@item.category_id %>
</select>
</td>
</tr>
<tr>
<td><b>Prioridad: </b></td>
<% @item.priority = 3 %>
<td><%= select "item","priority",[1,2,3,4,5] %></td>
</tr>
<tr>
<td><b>Privado? </b></td>
<td><%= check_box "item","private" %></td>
</tr>
<tr>
<td><b>Completado? </b></td>
<td><%= check_box "item", "done" %></td>
</tr>

Crear una lista desplegable para el campo fecha


d a t e_select ge nera u n r u di m e n ta rio m e n u d e s plegable p a ra ingresa r la fecha:
date_select "item", "due_date", :use_month_numbers => true
Document ación: ActionView::Helpers::DateHelper

Atrapar excepciones con Ruby


Desafor t u n a d a m e n te, date_select feli z m e n te ace p ta fechas co m o 3 1 d e Febrero. Rails
m u e re cua n d o inte n t a g uar d a r es ta fecha en la base d e d a t o s. Una for m a d e evitar est o es
at ra pa r este inte n t o d e g uar da r fallido u sa n d o rescue, u n m é t o d o d e m a n eja r excepcio ne s
d e Ruby
app\controllers\items_controller.rb (fragmento)
def create
begin
@item = Item.new(@params[:item])
if @item.save
flash['notice'] = 'Tarea creada exitosamente.'
redirect_to :action => 'list_by_priority'
else
@categories = Category.find_all
render_action 'new'
end
rescue
flash['notice'] = 'La tarea no se pudo grabar.'
redirect_to :action => 'new'
end
end
Ruby Document ación: Exceptions, Catch, and Throw

Página 28
Crear una lista desplegable desde una tabla de busqueda
Este es ot ro eje m plo d e Rails resolvien d o u n p r o ble m a d e co dificación diario d e u n a
fo r m a ext re m a d a m e n te econ ó mica. En es te eje m plo:
options_from_collection_for_select @categories, "id", "category", @item.category_id

options_from_collection_for_select lee t o d o s los regist ro s e n las categorias y los re n de ri za


co m o <option value=”[value of id]”>[value of category]</option>. El regist ro q ue es igual
a @item_category_id sera etiq uet a d o co m o ‘ selecciona d o’. Si es t o n o fuera s uficien te, el
có digo incluso u tili za esca pe s h t ml p a ra los d a t o s. Habil.
Document ación: ActionView::Helpers::FormOptionsHelper

Note q u e las cajas d e s plegables d e be n t raer los d a t o s d e algu n lugar – q ue sig nifica u n
agrega d o al con t r ola do r:
app\controllers\items_controller.rb (fragmento)
def new
@categories = Category.find_all
@item = Item.new
end

def edit
@categories = Category.find_all
@item = Item.find(@params[:id])
end

Crear una lista desplegable para la lista de constantes


Esta es u n a versión m a s si m ple d el caso a n te rior. Agregar u n a lista d e valores a u n a caja
d e selección en el có digo n o es sie m p re u n a b ue n a idea – es m a s fácil ca m biar los d a t o s
e n la t a bla q ue e ditar los valores en el có digo. De t o d a s for m a s, h ay casos d o n d e es u n a
a p r oxi m ació n p e rfecta m e n te vali da, e n t o nces en Rails h aga:
select "item","priority",[1,2,3,4,5]
Note t a m bién co m o in dicar u n a valor p o r d efecto en la linea d e có digo a n te rior.
Document ación: ActionView::Helpers::FormOptionsHelper

Crear una casilla de verificación


Ot ro re q ue ri mie n t o reg ular; o t r o hel per en Rails:
check_box "item","private"

Document ación: ActionView::Helpers::FormHelper

Toques finales
Modificar la hoja de estilos
Hast a es te p u n t o, la p a n t alla d e ‘Lista d e Tareas’ d e be ria f u ncio na r, y t a m bién d e beria
fu ncio nar el b o t ó n ‘New To Do’. Para p r o d ucir las p a n t allas m o s t ra d a s aq ui, t a m bié n hice
los sig uien te s ca m bios a la h oja d e es tilos:
public\stylesheets\ToDo.css
body { background-color: #c6c3c6; color: #333; }

.notice {
color: red;
background-color: white;
}

Página 29
h1 {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 14pt;
font-weight: bold;
}

table {
background-color:#e7e7e7;
border: outset 1px;
border-collapse: separate;
border-spacing: 1px;
}

td { border: inset 1px; }


.notice {
color: red;
background-color: white;
}
.lt_gray { background-color: #e7e7e7; }
.dk_gray { background-color: #d6d7d6; }
.hightlight_gray { background-color: #4a9284; }
.past_due { color: red }

La pantalla ‘Editar Tarea’


El re s to d el Dia 3 es la con t r ucció n d e la p a n t alla ‘Editar Tarea’, q u e es m uy si milar a
‘Nueva Tarea’. Estaba acos t u m b ra d o a m olest ar m e cua n d o los texto s d e sec u n d a ria
d ecian: esto q ueda co mo u n ejercicio f ácil p ara el lector, a ho ra es genial p o d er h acer lo
m i s m o con u s t e de s 1 0 .

Esto n o s lleva al final d el Dia 3 – y a h o ra la a plicació n n o se ve p a ra n a d a co m o u n


scaffol d d e Rails, p e ro bajo la s u p e rficie, t o davía u tiliza m o s u n gra n ra ngo d e
h e r ra mie n t a s d e Rails p a ra h acer el d e sa r rollo m a s fácil.

10 Pero no como los autores de los textos de secundaria, yo si muestro la respues t a en el Dia 4 :- ) -
vea app \ views \ite m s \ e dit.rht ml en la página 31

Página 30
Dia 4 con Rails
Las pantallas ‘Notas’
Enlazando ‘Notas’ con ‘Editar Tarea’
Aunque el código scaffold de las Notas le da todas las fácilidades, no quere mos que el
usuario invoque cualquiera de estas directa me n t e. En cambio, si un item no tiene
asociada una nota, queremo s poder crear una nota haciendo click en el ícono de Nota en
la pantalla de Edicion de tareas:

Ilustración 7 : Crear una nota nueva desde la pantalla


‘Editar Tarea’

Si ya existe una nota, queremo s poder editarla o borrarla haciendo click en el ícono
apropiado en la pantalla de Edicion de tareas:

Ilustración 8 : Editar o borrar una nota existente

Pri me ro q u e n a d a, vea m o s el có digo d e la p a n t alla ‘Editar Tarea’. Note co m o los bo t ó ne s


d e Notas ca m bian d e acuer d o a si la Nota existe o n o, y co m o el con t r ol es t ra n sferi do al
con t r ola d o r d e Notas:
app\views\items\edit.rhtml
<% @heading = "Edit To Do" %>
<%= error_messages_for 'item' %>
<%= start_form_tag :action => 'update', :id => @item %>
<table>

Página 31
<%= render_partial "form" %>
<tr>
<td><b>Notes: </b></td>
<% if @item.note_id.nil? %>
<td>None</td>
<td><%= link_to_image "note", :controller => "notes", :action => "new", :id =>
@item.id %></td>
<% else %>
<td><%=h @item.note.more_notes %></td>
<td><%= link_to_image "edit_button", :controller => "notes", :action => "edit",
:id => @item.note_id %></td>
<td><%= link_to_image "delete_button", {:controller => "notes", :action =>
"destroy", :id => @item.note_id }, :confirm => "Are you sure you want to delete this
note?" %></td>
<% end %>
</tr>
</table>
<hr />
<%= submit_tag "Save" %>
<%= submit_tag "Cancel", {:type => 'button', :onClick=>"parent.location='" + url_for(
:action => 'list' ) + "'" } %>
<%= end_form_tag %>

La pantalla ‘Editar Notas’


Editar una nota existente es muy simple. Esta es la plantilla:
app\views\notes\edit.rhtml
<% @heading = "Edit Note" %>
<%= start_form_tag :action => 'update', :id => @note %>
<%= render_partial "form" %>
<%= submit_tag "Save" %>
<%= submit_tag "Cancel", {:type => 'button', :onClick=>"parent.location='" +
url_for( :controller => 'items', :action => 'list' ) + "'" } %>
<%= end_form_tag %>

y el parcial:
app\views\notes\_form.rhtml
<table>
<tr>
<td><label for="note_more_notes">More notes</label></td>
<td><%= text_area 'note', 'more_notes' %></td>
</tr>
</table>

Una vez que la acción update o destroy de la tabla Notas es completada, queremos regresar
a la pantalla de ‘Lista de Tareas’:
app\controllers\notes_controller.rb (fragmento)
def update
@note = Note.find(@params[:id])
if @note.update_attributes(@params[:note])
flash['notice'] = 'Note was successfully updated.'
redirect_to :controller => 'items', :action => 'list'
else
render_action 'edit'
end
end

def destroy
Note.find(@params[:id]).destroy
redirect_to :controller => 'items', :action => 'list'
end
Recuer de las reglas d e integ ri da d refere ncial q ue ya h a n si d o crea da s se asegu rara n d e

Página 32
q ue cua n d o u n a n o t a es eli mina da, cualq uier refere ncia a ella sera re m ovida d el Ite m
t a m bié n (vea Integridad Refere ncial en la p ágina 2 1 ).

La pantalla de ‘Nota Nueva’


Crear es u n p oco m a s difícil. Quere m o s h acer lo siguien te:

• guar d a r u n a n ueva n o ta e n la t abla d e Notas


• e nco n t ra r el id d e u n n u evo regist ro crea d o en la ta bla d e Notas
• regist ra r es te id en el ca m p o n o tes_id d el regist ro asocia do en la t abla d e Ite m s

Las variables d e Sesió n n o s p r oveen u n a for m a ú til d e m a n t e ne r d a t o s e n t re p a n t allas –


p o d e m o s u tili za rlas a q ui p a ra g ua r d a r el Id d el regist ro en la t abla d e Notas.
Document ación: ActionController::Base

Guardar y traer Datos usando variables de Sesión


Primero que nada, cuando creamos un nuevo registro de Nota, pasamo s el id del Item que
estamo s editando:
app\views\items\edit.rhtml (fragmento)
<td><%= link_to_image "note", :controller => "notes", :action => "new", :id =>
@item.id %></td>

El método new en el controlador Notes guarda esto en una variable de sesión :


app\controllers\notes_controller.rb (fragmento)
def new
@session[:item_id] = @params[:id]
@note = Note.new
end

La plantilla ‘Notas Nuevas’ no tienen sorpresas:


app\views\notes\new.rhtml
<% @heading = "New Note" %>
<%= start_form_tag :action => 'create' %>
<%= render_partial "form" %>
<%= submit_tag "Save" %>
<%= submit_tag "Cancel", {:type => 'button', :onClick=>"parent.location='" + url_for(
:controller => 'items', :action => 'list' ) + "'" } %>
<%= end_form_tag %>

El método create trae los datos de la variable de sesión de nuevo y lo usa para encontrar
el registro en la tabla de Items. Luego actualiza el campo note_id en la tabla Item con el id
del registro que se acaba de crear en la tabla de Notas, y retorna al controlador Items de
nuevo:
app\controllers\notes_controller.rb (fragmento)
def create
@note = Note.new(@params[:note])
if @note.save
flash['notice'] = 'Note was successfully created.'
@item = Item.find(@session[:item_id])
@item.update_attribute(:note_id, @note.id)
redirect_to :controller => 'items', :action => 'list'
else
render_action 'new'
end
end

Página 33
Cambiar la pantalla de ‘Categorias’
No hay demasiado por hacer en el sistema ahora, a parte de acomo da r las plantillas
creadas en los dias anteriores para que tengan el mismo estilo que los botónes de
navegación:
app\views\categories\list.rhtml
<% @heading = "Categories" %>
<form action="/categories/new" method="post">
<table>
<tr>
<th>Category</th>
<th>Created</th>
<th>Updated</th>
</tr>
<% for category in @categories %>
<tr>
<td><%=h category["category"] %></td>
<td><%= category["created_on"].strftime("%I:%M %p %d-%b-%y") %></td>
<td><%= category["updated_on"].strftime("%I:%M %p %d-%b-%y") %></td>
<td><%= link_to_image 'edit', { :action => 'edit', :id => category.id } %></td>
<td><%= link_to_image 'delete', { :action => 'destroy', :id => category.id },
:confirm => 'Are you sure you want to delete this category?' %></td>
</tr>
<% end %>
</table>
<hr />
<input type="submit" value="New Category..." />
<input type="button" value="To Dos" onClick="parent.location='<%= url_for(
:controller => 'items', :action => 'list' ) %>'">
</form>

app\views\categories\new.rhtml
<% @heading = "Add new Category" %>
<%= error_messages_for 'category' %>
<%= start_form_tag :action => 'create' %>
<%= render_partial "form" %>
<hr />
<input type="submit" value="Save" />
<input type="button" value="Cancel" onClick="parent.location='<%= url_for( :action
=> 'list' ) %>'">
<%= end_form_tag %>

app\views\categories\edit.rhtml
<% @heading = "Rename Category" %>
<%= error_messages_for 'category' %>
<%= start_form_tag :action => 'update', :id => @category %>
<%= render_partial "form" %>
<hr />
<input type="submit" value="Update" />
<input type="button" value="Cancel" onClick="parent.location='<%= url_for( :action
=> 'list' ) %>'">
<%= end_form_tag %>

Navegación a traves del sistema


Los ca mi no s finales d e n avegación a t raves d el sis te m a so n m o s t r a d o s a con tin uació n.
Cualq uier có digo scaffol d re d u n d a n te – eje m plo los arc hivos show.rhtml – p u e n d e ser
si m ple m e n t e eli mi na d o s. Esa es la belle za d el có digo scaffol d – n o le cos to ni ng u n
esf ue r z o crear el có digo e n p ri me r lugar, y u na ve z q u e sirvio s u p r o p o si to, di recta m e n te
lo p u e d e eli mi nar.

Página 34
Nueva
Tarea

Nueva
Categoria
Lista
Tareas Nueva
Nota
Lista
Categorias

Editar
Editar Not a
Tarea
Editar
Categoria

Ilustración 9 Caminos de navegación a traves de la aplicación

Colocar una página de inicio para la Aplicación


Co m o p a so final, necesita m o s eli mi na r la p a n t alla p o r d efecto 'Bienveni do a Rails' si el
u s ua rio ingresa e n s u n avega d o r http://todo. Hay d o s p a so s:
• Agregar u n a p ági na d e inicio al arc hivo Routes:
config\routes.rb (fragmento)
map.connect '', :controller => 'items'
• re n o m b ra r public\index.html public\index.html.orig

Descargar una copia de esta aplicación


Si q uiere u n a co pia d e la a plicación ‘Lista d e Tareas’ p a ra j ugar, h ay u n enlace en
h t t p: / / r ails.ho melin ux.org. Necesita
• u sa r Rails p a ra ar m a r la es t r uct u ra d e directo rios (vea Rails en la p ágina 3 )
• d e scarga r el archivo todo_app.zip en el n uevo di recto rio crea d o ToDo
• d e sco m p ri mi r los arc hivos unzip -o todo_app.zip
• re n o m b ra r public\index.html public\index.html.orig
• si d e sea u sa r la ba se d e d a t o s d e eje m plo, mysql -uroot -p < db/ToDo.sql

Y finalmente
Espero q ue e nc ue n t re es te d oc u m e n t o ú til – sie m p re m e p o n e co n te n t o recibir
co me n t arios, b ue n o s o m alos, a j p mcc@users.so u rceforge.ne t.
Co me n ta rios d e la versió n en es pa ñ ol a e m m a n u eln _at_ g m ail.co m

Feliz d e sa r rollo con Rails!

Página 35
Apéndice – Cambios posteriores
Des p ues d e escribir ‘Cuat ro Dias’, recibi m u c h o s co me n t a rio s q ue ay u d a ro n a m ej ora r la
calida d d el d oc u m e n t o. Una p reg u n t a a pa recio re pe tí da me n te - “co m o act uali zo m a s d e
u n regist ro d e s de la m i s m a p a n t alla” - en to nces a q ui h ay a pé n dice cub rien d o esta s
Pregu n t a s Frecue n te s. No es el conce p t o m a s fácil d e d o mi na r, y es u n area q u e es pe ra ria
q ue a pa re zca n m a s “ayu da n te s” (hel per s) e n el f ut u r o.

Actualizaciones Multiples
En la captura de pantalla de abajo, el usuario puede tildar / d e s tildar varias “Tareas”
usando las cajas de verificación en la columna de la izquierda, y luego presionar
“Guardar” para guardar los resultados en la base de datos.

Ilustración 10 : Actualizaciones multiples

View
Rails soporta actualizaciones multiples con otra convención de nombres, que es agregar
el id del registro que se esta editan do al nombre entre corchetes [ ]. Esto permite
seleccionar un registro en particular desde multiples registros en la pantalla.

Trabajemos hacia atras desde el HTML que estamos generan do. Esto es lo que se ve para
el registro con id = 6:

<td style="text-align: center">


<input type="checkbox" id="item_done" name="item[6][done]" value="1" checked />
<input name="item[6][done]" type="hidden" value="0" />
</td>

(“checked” (seleccionado) es omitido si la casilla de verificación no esta chequeada)

Una forma de generar este código es:


app\view\items\_list_stripes.rhtm (fragmento)
<td style="text-align: center">
<%=check_box_tag("item["+list_stripes.id.to_s+"][done]","1",list_stripes["done"]==1)
%>

Página 37
<%=hidden_field_tag("item["+list_stripes.id.to_s+"][done]","0") %>
</td>

Los p a rá m e t r o s p a ra check_box_tag so n name, value = "1", checked = false, options = {};


p a ra hidden_field_tag name, value = nil, options = {}
Document ación: ActionView::Helpers::FormTagHelper

Ade m a s necesita m o s u n bo tó n Guar d a r (Save):


app\views\items\list.rhtml (fragmento)
<% @heading = "To Do List" %>
<%= start_form_tag :action => 'updater' %>
<table>
...
</table>
<hr />
<%= submit_tag "Save" %>
<%= submit_tag "New To Do...", {:type => 'button', :onClick=>"parent.location='" +
url_for( :controller => 'items', :action => 'new' ) + "'" } %>
<%= submit_tag "Categories...", {:type => 'button', :onClick=>"parent.location='" +
url_for( :controller => 'categories', :action => 'list' ) + "'" } %>
<%= end_form_tag %>
<%= "Page: " + págination_links(@item_pages, :params => { :action => @params["action"]
|| "index" }) + "<hr />" if @item_pages.page_count>1 %>

Controlador
Lo q ue re t o r na d el co nt rola d o r cua n d o se p re sio na el b o t ó n “Guar d ar” es el siguien te
h a s h:
params: {
:controller=>"items",
:item=> {
"6"=>{"done"=>"0"},
... etc...
"5"=>{"done"=>"1"}
},
:action=>"updater"
}

Esta m o s interesa d o s en la p a r t e d e :item. Por eje m plo, la linea e n negrita significa “el
regist ro co n el id = 6 tiene el valor d el ca m p o done en 0”. Des de aq ui, es u n t rabajo
ba s ta n te si m ple el d e act uali za r la t abla d e Items:
app\controller\items_controller (fragmento)
def updater
@params[:item].each { |item_id, attr|
item = Item.find(item_id)
item.update_attribute(:done,attr[:done])
}
redirect_to :action => 'list'
end

each coloca “6” e n la variable item_id, y “do ne” = > “0” e n attr.
Ruby Document ación: class Array

Este có digo f u ncio na, p e ro si ve q ue es ta p a sa n d o en development.log, vera q ue Rails esta


t rayen d o y act uali za n d o ca da regist ro, sea m o difica do o n o. No solo est o est a crean d o
act u ali zacio nes in necesa rias en la ba se d e d a t o s, p e r o t a m bié n sig nifica q ue updated_on
t a m bié n esta n sien d o m o dificad o, q ue n o es en realida d lo q ue d e sea m o s. Mucho m ej o r

Página 38
es solo act u ali za r si ‘done’ h a ca m bia do, p e ro est o significa te ner q ue escribir m a s có digo
:-(
app\controller\items_controller (fragmento)
def updater
@params[:item].each { |item_id, contents|
item = Item.find(item_id)
if item.done != contents[:done].to_i
item.update_attribute(:done,contents[:done])
end
}
redirect_to :action => 'list'
end

Note q u e necesita m o s co nver tir la cade na done a u n en te ro u s a n d o to_i asi p o d e m o s


co m p a ra r los valores. Este es el ti po d e te m a en el q u e fácil me n te se falla – vale la p e n a
cheq uear development.log de ve z en cua n d o p a ra asegu ra rse d e q ue Rails est a h acien d o lo
q ue u n o es pe ra.

Consideraciones de la interfaz de usuario


Este có digo f u ncio na, y p u e de ser a plica d o p a ra h acer cualq uier ca m p o d e la p a n t alla
e di table (otro ejercicio si m ple p a ra el lector : - ). Si p r ese n t a algu n as p reg u n t a s
interesa n tes acerca d e q ue es pe ra el u s u a rio. Que p a sa si el u s u a rio ca m bia alg u n a s d e las
cajas d e verificación, y luego p re sio na “Nueva Tarea...”, o si re - or de na la p a n t alla, si n
p re sio na r “Guar da r”? El siste m a d e bería sie m p re “Guar d a r” a n tes d e reali zar cualq uier
o t ra acció n? Mas ejercicios p a ra el lector...

Todavía para hacer


En la p ági na 2 5 deje u n ejercicio con list_by_category p a ra el lecto r. Fue m a s fácil d e lo
q ue p a recia – inclu so, t o davia est oy b u sca n d o u n a for m a m a s elega n te e n ‘Rails’ d e
o r de n a r p o r ca m p o en u n a t a bla d e b u s q u e d a. Ter mi né co n es te h o r rible có digo:
app\controller\items_controller (fragmento)
def list_by_category
@item_pages = Paginator.new self, Item.count, 10, @params['page']
@items = Item.find_by_sql 'SELECT i.*, c.category FROM categories c, items i ' +
'WHERE ( c.id = i.category_id ) '+
'ORDER BY c.category ' +
'LIMIT 10 ' +
"OFFSET #{@item_pages.current.to_sql[1]}"
render_action 'list'
end

Si alguien tiene u n a m ej o r s ol ución, p o r favor h aga m elo saber. Dejo este có digo co m o
eje m plo d e q u e si t o d o falla, Rails n o lo d ejara t raba d o p e ro le p e r mi tira o r de n ar con este
viejo có digo!

Disfr u te el d e sa r rollo con Rails!

Página 39
Indice de Terminos de Rails y Ruby usados en este
Documento
A new (nuevo) ........................................................10
action_na me .......................................................12 O
B options_fro m_collection_for_select ............29
before_type_cast ...............................................20 P
belongs_to (pertenece a).................................20 paginate ...............................................................14
C págination_links ...............................................18
check_box ............................................................29 Partial o Parcial .................................................11
check_box_tag ...................................................38 previous ...............................................................15
confirm .........................................................15, 24 R
content_colum n s ..............................................15 redirect_to ...........................................................10
content_for_layout ...........................................12 render_collection_of_partials .......................26
created_at ..............................................................5 render_partial .............................................12, 25
created_on ......................................................5, 13 render_te m plate ................................................10
current .................................................................15 rescue ...................................................................28
D S
date_select ..........................................................28 save (guardar) ....................................................10
destroy (destruir) ..............................................10 select .....................................................................29
destroy_all ..........................................................24 start_form_tag ...................................................12
developme n t.log ....................................3, 10, 39 strftime ................................................................17
E stylesheet_link_tag ...........................................12
end_for m_tag .....................................................12 submit_tag ..........................................................12
error_messages_for .........................................13 T
F Template o Plantilla .........................................11
find (encontrar) .................................................10 text_field .............................................................13
find_all (encontrar todos) ..............................10 U
Flash ......................................................................16 update_attribut e ...............................................38
H update_attribut es (actualizar atribut os) ...10
h .............................................................................15 updated_at ............................................................5
helper (ayudante) ..............................................12 updated_on ....................................................5, 13
hidden_field_tag ...............................................38 url_for ..................................................................25
HTML....................................................................15 V
human_att ribu te_na m e ...................................15 validates_associated (validar asociaciones) ...
human_na m e .....................................................15 20
I validates_form at_of .........................................20
id ..............................................................................5 validates_inclusion_of .....................................20
Integridad Referencial .....................................21 validates_lengt h_of .....................................7, 20
L validates_presence_of .....................................20
Layout ...................................................................11 validates_uniq ue ness_of ...................................7
link_to ..................................................................12 variable de sesión .............................................33
link_to_image .....................................................24 .
lock_versión ..........................................................5 .each ......................................................................38
N

Página 41

You might also like