• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
My cool new Slideshow!
 

My cool new Slideshow!

on

  • 200 views

 

Statistics

Views

Total Views
200
Views on SlideShare
200
Embed Views
0

Actions

Likes
0
Downloads
0
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    My cool new Slideshow! My cool new Slideshow! Document Transcript

    • 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 Filesrubylibrubygemsn.ndocactionpack- n.n.nrdocindex.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:wwwwebroot, que etiqueto como mi disco w: para acortar el tipeo: C:> subst w: c:wwwwebroot 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:winntsystem32driversetchosts (fragmento) 127.0.0.1 todo Definir la aplicación en el archivo de configuración de Apache Apache2confhttpd.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: configenvironment.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 configdatabase.yml configdatabase.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: appcontrollerscategory_controller.rb apphelperscategory_helper.rb appviewscategories appviewslayouts 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: appcontrollerscategory_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: appmodelscategory.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 appcontrollerscategory_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: appcontrollerscategories_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 appviewslayouts e n appviews<controller> e n appviews<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 appviewslayouts 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: appviewslayoutscategories.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 appviewscategories‘acción’.rhtml. El nuevo .rhtml creado por el script scaffold es mostra do a continuación: appviewscategoriesnew.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
    • appviews‘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. appviewscategories_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 : appviewscategoriesnew.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: appviewscategorieslist.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: appcontrollerscategories_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’: appcontrollerscategories_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): appviewslayoutscategories.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: publicstylesheetsscaffold.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: appviewscategorieslist.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: appviewscategories_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):: appviewscategoriesEdit.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' %> appviewscategoriesNew.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: appmodelsitem.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: appmodelsnote.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 : appmodelsitem.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. appmodelsitem.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: appmodelsnote.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 appviewslayouts*.rhtml, y ree m placelos p o r u n arc hivo co m ú n application.rhtml. appviewslayoutsapplication.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
    • appviewsitemslist.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: appcontrollersitems_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: appcontrollersitems_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: apphelpersapplication_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: appcontrollersapplication.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: appviewsitems_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: publicstylesheetsToDo.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: appviewsitemsnew.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’: appviewsitems_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 appcontrollersitems_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: appcontrollersitems_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: publicstylesheetsToDo.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: appviewsitemsedit.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: appviewsnotesedit.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: appviewsnotes_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’: appcontrollersnotes_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: appviewsitemsedit.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 : appcontrollersnotes_controller.rb (fragmento) def new @session[:item_id] = @params[:id] @note = Note.new end La plantilla ‘Notas Nuevas’ no tienen sorpresas: appviewsnotesnew.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: appcontrollersnotes_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: appviewscategorieslist.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> appviewscategoriesnew.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 %> appviewscategoriesedit.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: configroutes.rb (fragmento) map.connect '', :controller => 'items' • re n o m b ra r publicindex.html publicindex.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 publicindex.html publicindex.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: appviewitems_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): appviewsitemslist.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: appcontrolleritems_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 :-( appcontrolleritems_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: appcontrolleritems_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