my cool new slideshow!

45
Cuatro Dias Cuatro Dias con Rails con Rails compilado por John McCreesh traducción por Emmanuel N. Millán

Upload: gealgaro

Post on 20-Aug-2015

109 views

Category:

Technology


0 download

TRANSCRIPT

Cuatro DiasCuatro Dias con Railscon Rails

compilado por John McCreeshtraducción por Emmanuel N. Millán

Tabla de ContenidosIntroducción ...................................................................................................................................................1

Día 1 con Rails ...............................................................................................................................................3

La aplicación ‘Lista de Tareas’ .............................................................................................................3Ejecutar el script de Rails ......................................................................................................................3Agregar la aplicación al servidor Web...............................................................................................3

Definir la aplicación en el archivo de hosts ...............................................................................3Definir la aplicación en el archivo de configuración de Apache .........................................3Cambiar a fastcgi ................................................................................................................................4Chequear que Rails este funcionando ..........................................................................................4Versiones de Rails ..............................................................................................................................4

Configurar la Base de Datos .................................................................................................................4Crear la tabla Categorias ..................................................................................................................5

Definición MySQL..........................................................................................................................5Modelo de Datos ............................................................................................................................5

Scaffold .......................................................................................................................................................5Realzar el Modelo .....................................................................................................................................6

Crear reglas de validación de datos ..............................................................................................7

Dia 2 con Rails ...............................................................................................................................................9

El código generado Scaffold .................................................................................................................9El controlador ......................................................................................................................................9La Vista ................................................................................................................................................11

Layout .............................................................................................................................................11Template (plantilla) ....................................................................................................................12Partial (parcial) .............................................................................................................................12La vista de renderizado para la acción “New”....................................................................13Analizando la vista de la acción ‘List’...................................................................................14

Modificar el código generado por Scaffold ...................................................................................16El controlador ....................................................................................................................................16La Vista (View)...................................................................................................................................16

Mostrar mensajes Flash .............................................................................................................16Compartir variables entre la plantilla y el Layout ............................................................17Atando las pantallas de Edit y New.......................................................................................18

Día 3 con Rails ............................................................................................................................................19

La tabla ‘Items’ .......................................................................................................................................19Definición MySQL de la tabla ........................................................................................................19El Modelo .............................................................................................................................................19

Validar los links entre las tablas ............................................................................................20Validar la entrada del usuario .................................................................................................20

La tabla de ‘Notas’ .................................................................................................................................20Definición de la tabla MySQL........................................................................................................20El modelo ............................................................................................................................................21

Usar un Modelo para mantener Integridad Referencial ..................................................21Mas de Scaffold ......................................................................................................................................22Mas acerca de Vistas .............................................................................................................................22

Crear un Layout para la Aplicación ............................................................................................22La pantalla ‘Lista de tareas’ ...........................................................................................................23

Eliminar ‘tareas’ completadas haciendo click en un ícono ............................................24Cambiar el modo de ordenamiento haciendo click en el Encabezado de la Columna .........................................................................................................................................24Agregar el Helper ........................................................................................................................25Usar botónes de navegación Javascript ................................................................................25Formatear una Tabla con un Parcial ......................................................................................25

Formato basado en el valor de los Datos ............................................................................27Manejar valores perdidos en una busqueda ......................................................................27

La pantalla ‘Nueva Tarea’ ...............................................................................................................27Crear una lista desplegable para el campo fecha ..............................................................28Atrapar excepciones con Ruby ................................................................................................28Crear una lista desplegable desde una tabla de busqueda ............................................29Crear una lista desplegable para la lista de constantes ..................................................29Crear una casilla de verificación ............................................................................................29

Toques finales ........................................................................................................................................29Modificar la hoja de estilos ...........................................................................................................29La pantalla ‘Editar Tarea’...............................................................................................................30

Dia 4 con Rails ............................................................................................................................................31

Las pantallas ‘Notas’ .............................................................................................................................31Enlazando ‘Notas’ con ‘Editar Tarea’ ..........................................................................................31La pantalla ‘Editar Notas’ ...............................................................................................................32La pantalla de ‘Nota Nueva’...........................................................................................................33

Guardar y traer Datos usando variables de Sesión ...........................................................33Cambiar la pantalla de ‘Categorias’ .................................................................................................34Navegación a traves del sistema .......................................................................................................34Descargar una copia de esta aplicación ..........................................................................................35Y finalmente ............................................................................................................................................35

Apéndice – Cambios posteriores ..........................................................................................................37

Actualizaciones Multiples ...................................................................................................................37View......................................................................................................................................................37Controlador ........................................................................................................................................38Consideraciones de la interfaz de usuario ...............................................................................39

Todavía para hacer ................................................................................................................................39

Introducción

Han habido varias demandas extravagantes hechas acerca de Rails. Por ejemplo, un articulo publicado en OnLAMP.com 1 demandando 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 funcionando con “scaffold” virtualmente sin código.

Mientras que esto es impresionante, desarrolladores web “reales” saben que esto es humo y espejos. aplicaciónes ‘reales’ no son tan simples como eso. ¿Qué es realmente lo que esta pasando 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 documentación on- line, de hecho, posiblemente esta demasiado bien documentado para principiantes, con mas de 30.000 palabras de documentación on- line en el formato de manual de referencia. Lo que esta faltando en un roadmap (railmap?? - mapa del camino) apuntando a las páginas claves que necesitas saber para comenzar a desarrollar con Rails.

Este documento está para llenar ese vacio. Asume que ya tienes Ruby y Rails en funcionamiento 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 posicionandose 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 documentacio de Rails o de Ruby donde puedes aprender más.

‘Dia 3 con Rails’ toma scaffold y comienza a construir algo reconocible como una aplicación “real”. Todo el tiempo, esta contruyendo su propia caja de herramientas con Rails. Lo mas importante de todo, deberia también sentirse comodo con la documentació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 mantener la integridad referencial. Al final, tendra una aplicación en funcionamiento, suficientes herramientas como para comenzar, y el conocimiento 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 documento contiene referencias destacadas, a cualquiera de los siguientes sitios:

• Docu mentación – La docu mentación de Rails en h t t p: / / a pi.rubyonrails.com (Esta docu men tación ta mbién esta instalada en su PC como par te de la ins talación de gems ubicada en u n lugar como C:\Program Files\ruby\lib\ruby\gems\n.n\doc\actionpack-n.n.n\rdoc\index.html)

• Ruby Docu mentación – “Progra m ming Ruby - The Prag matic Progra m mer's Guide” disponible en linea y para bajar en h t t p: / / www.ruby - doc.org / docs / r uby - doc -bun dle /Progra m mingRuby /index.ht ml

1 Rolling with Ruby on Rails, Curt Hibbs 20- Jan2005 http: / / www.onlamp.com / p u b / a / o nla mp / 2 0 05 / 0 1 / 2 0 / r a ils.htm l

Página 1

Reconocimientos : m uchas gracias a la gente en el canal irc2 y en la lista de correo 3. El regist ro de archivos en linea fue u na invaluable asis tencia mien t ras aprendia Rails y Ruby.

Versión: 2.3 usando la versión 0.12.1 de Rails – vea http: / / r ai ls.homelinux.org para la última versión y para bajar una copia del futuro código. Documento escrito y pdf generado con OpenOffice.org 'Writer'.

Copyright : este trabajo tiene copyright ©2005 John McCreesh [email protected] y esta bajo la licencia Creative Commons Attribution-NonCommercial - ShareAlike License . Para ver una copia de esta licencia, visite http: / / c rea tivecommons.org / licenses / by - nc- sa/2.0 / o envie una carta a Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.

2 irc:/ / i rc.freenode.org / r ubyonrails 3 http: / / li s ts.rubyonrails.org /mailman / l is tinfo / rails

Página 2

Día 1 con Rails

La aplicación ‘Lista de Tareas’Este docu mento sigue la cons t rucción de u na si mple aplicación de “lista de tareas” – el tipo de cosa que tienes en tu PDA, con una lista de ite ms, agrupados en categorias, con no tas opcionales (para ver u na adelan to de como se va a ver, vea Ilustración 5: La pantallade ‘Lista de Tareas’ en la página 23).

Ejecutar el script de RailsEste 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\webrootC:\> w:W:\> rails ToDoW:\> cd ToDoW:\ToDo>

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

appcontiene 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

logregistros 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!

publicel directorio disponible para Apache, que incluye imagenes, javascripts, y subdirectorios para stylesheets

Agregar la aplicación al servidor WebComo yo estoy ejecutando 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 hostsC:\winnt\system32\drivers\etc\hosts (fragmento)

127.0.0.1 todo

Definir la aplicación en el archivo de configuración de ApacheApache2\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 fastcgiRewriteRule ^(.*)$ 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 mento que leas este docu men to, Rails p robablemente haya avanzado varias versiónes. Si intentas avan zar a t raves de este docu men to, chequea la versión ins talada en tu PC:W:\ToDo>gem list --local

Si son dis tin tas a las versiónes listadas abajo, entonces yo fuer te mente aconsejaria que baje las versiónes usadas en “Cuat ro dias con Rails”, ejem plo: W:\ToDo>gem install rails --versión 0.12.1

Esto no ro m pera nada; la libreria gems de Ruby es ta diseñada para ma nejar m ultiples versiónes. Entonces p uede for zar a Rails a que use las versiónes u tilizadas en “Cuatro Dias” en la aplicación ‘Lista de Tareas’ especificando:

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 razón para u sar la mis ma versión es m uy sim ple. ‘Cuat ro Dias’ usa m ucho código generado auto maticamente po r Rails. Mientras Rails se desar rolla, ta mbién lo hace es te código – desafort unada mente, es te docu mento no lo hace (hasta que se p roduce una nueva versión!). Entonces, has tu vida fácil, y m an tene la mis ma versión que se u sa en ‘Cuat ro Dias’. Una vez que hayas ter minado de t rabajar con ‘Cuatro Dias’, ve a la úl ti ma y gran versión de Rails y ve que mejoras los desarrolladores de Rails han realizado.

Configurar la Base de DatosHe configurado 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 automaticamente mantendra los campos llamados created_at/created_on o

updated_at/updated_on, entonces es una buena idea agregarlos

Documentación: ActiveRecord::Timestamp

• Tip útil: si esta construyendo 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.

Documentació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>

que crea u n archivo category.rb, y dos archivos de p r ueba category_controller_test.rb y categories.yml. Agregare mos algunas ent radas en el m o delo de da tos en u n minu to – dejelo vacio po r el m o mento.

ScaffoldEl 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.rbapp\helpers\category_helper.rbapp\views\categoriesapp\views\layouts

Si no ha visto el truco modelo / scaffold en funcionamiento 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 :categoryend

Documentación: ActionController::Scaffolding

Apun te su navegador a http://todo/category y ad mire que tan ingenioso es : - )

Para averigüar que tan ingenioso no es, inten te agregar la mis ma categoria dos veces. Rails f racasará y dara u n sucio mensaje de error ‘ActiveRecord::State men tInvalid in Category#create’. Puede ar reglar esto agregando validación al Modelo.

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

Página 6

Ilustración 1: pantalla 'Lista' Scaffold

Crear reglas de validación de datos

Rails otorga mucho manejo de errores gratis (casi). Para demostrar 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 automaticamente chequearan que:

• validates_length_of: el campo no este en vacio y no sea m uy largo• validates_uniqueness_of: valores du plicados son at rapados. No me gus ta el mensaje de

error por defecto de Rails - ‘xxx has already been taken’ - entonces doy mi p ropio mensaje. Esta es una caracterís tica general de Rails – p rimero p r uebe los valores por defecto, si no le gus tan, sobreescribalos.

Documentación: ActiveRecord::Validations::ClassMethods

Página 7

Para p robar es to, ahora intenta agregar un regist ro d u plicado de nuevo. Esta vez, Rails ma neja el error en vez de “rom perse” - vea abajo. El estilo es ta un poco en su cara – no es la in terfaz de u suario m as sutil. De todas for mas, que espera si es gratis?

Página 8

Ilustración 2: Capturando errores de datos

Dia 2 con RailsPara progresar mas alla de este punto, necesitamos ver que esta pasando detras de la escena. Durante el dia 2, trabajaremos sistematicamente 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ámicamente. Ejecutando scaffold como un script , podemos obtener todo el código escrito al disco donde lo podemos investigar y luego comenzar a modificarlo para ajustarse a nuestros requerimientos.

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 pequeña bizar ra convención de no mbres – nos he mos m ovido del singular a plural, entonces para usar el n uevo código necesita apuntar el navegador a http://todo/categories. De hecho, pa ra evitar confusiones, es mejor borrar app\controllers\category_controller.rb etc en caso de que lo ejecute acciden talmente.

El código generado Scaffold

El controlador

Veamos el código det ras del cont rolador. El cont rolador es don de descansa la p rogra mación lógica de la aplicación. Interactua con el u suario usando vistas (views), y con la base de datos a t raves de los m o delos (models). Deberia po der leer el cont rolador y ver como la aplicación esta unida.

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' endend

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 nombre - ‘show.rthml’. Este comportamiento 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), simplemente lleva al usuario a la acción list.

Documentació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

Documentación: ActiveRecord::Base

Note como una actividad lógica desde la perspectiva del u suario p uede requerir dos pasos a t raves del con trolador: por eje mplo, actualizar un regist ro en la tabla. Cuando el u suario selecciona ‘Edit’, el con trolador extrae el regist ro que se desea editar del m o delo, y renderiza la vista edit. Cuando el usuario finalizo la edición, la vista edit invoca la acción update, que actualiza el m o delo y luego invoca la acción show.

La Vista

Las vistas son do nde se define la interfaz del u suario. Rails p uede renderizar la página HTML final p resen tada al u suario desde t res co m ponentes:

Layout Template - Plantilla Partial - Parcial

en app\views\layouts\

por defecto: application.rhtml

o <controller>.rhtml

en app\views\<controller>\

por defecto: <action>.rhtml

en app\views\<controller>\

por defecto _<partial>.rhtml

• Un Layout p rovee código com un usado po r todas las acciónes, tipicamente el comienzo y final del HTML enviado al navegador.

• Un Tem plate o Plantilla p rovee el código especifico a cada acción, ejem plo código de ‘List’, código de ‘Edit’, etc.

• Un Partial o Parcial p rovee código co mun - ‘subrutinas’ - que p uede ser usado en m ultiples acciónes – ejemplo: código usado para m os t rar tablas en u n for 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 automáticamente como layout del controlador a menos que explícitamente se indique lo contrario.

Un layout con el nombre de application.rhtml o application.rxml sera configurado como el controlador por defecto si no existe un layout con el mismo nombre que el controlador actual, y no existe un layout asignado explicitamente.

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 renderizado sin considerar la acción que se este ejecutando. Contiene etiquetas estandar 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 renderizado

Página 11

de Rails como se muestra a continuación:

• action_name es un método ActionController que devuelve el nombre de la acción que el controlador esta procesando (ejemplo ‘List’) - esto coloca el titulo de la página apropiado, dependiendo de la acción que se esta ejecutando.

Documentación: ActionController::Base

• stylesheet_link_tag es un helper (ayudante) de Rails – una manera perezosa de generar código. Hay muchos de estos ‘ayudantes’ dentro de Rails. Este simplemente genera el siguiente código HTML: <link href="/stylesheets/scaffold.css" media="screen" rel="Stylesheet" type="text/css" />

Documentación: ActionView::Helpers::AssetTagHelper

• content_for_layout es la clave de lo que pasa a continuación. Permite a un unico layout estandar tener contenido dinamico insertado en tiempo de renderizado basado en la acción ejecutada (ejemplo ‘edit’, ‘new’, ‘list’). Este contenido dinamico proviene de un Template (plantilla) con el mismo nombre – ver abajo.

Documentación: ActionController::Layout::ClassMethods.

Template (plantilla)

Convención de nombres de Rails: las plantillas estan guardadas en app\views\categories\‘acción’.rhtml.

El nuevo .rhtml creado por el script scaffold es mostrado 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ámetro “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

Documentación: ActionView::Helpers::FormTagHelper

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

Documentación: ActionView::Partials

• link_to simplemente crea un link – la parte mas fundamental de HTML... <a href="/categories/list">Back</a>

Documentació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).

Scaffold u sa el mis mo código para p rocesar a mbas ‘edit’ y ‘new’ acciónes, en tonces coloca el código en un parcial, invocado po r el método 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_for devuelve 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 correspondientes declaraciones en la hoja de estilos creada por el script generar scaffold.

Documentació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ámetro es el nombre de la tabla; el segundo es el nombre del campo.

Documentación: ActionView::Helpers::FormHelper

Note u n pequeño bug en Rails – sabe como no crear u n cam po de ent rada para los cam pos reservados created_on y u p dated_on, pero aun asi genera las etiquetas para 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’ son si milares a la vista ‘New’. ‘List’ contiene algunos t rucos nuevos. Recuerde como el cont rolador ejecuto la siguien te pieza de código antes de renderiza r la plan tilla ‘List’: @category_pages, @categories = paginate :category, :per_page => 10

paginate p uebla la variable de ins tancia @categories con regist ros or denados de la tabla Categories, :per_page regist ra po r vez, y con tiene toda la lógica para la navegación a la página siguiente / an terior. @category_pages es u na ins tancia a Paginator. Como son usadas en la plantilla se explican al final de la siguiente sección.

Documentación: ActionController::Pagination

La plantilla se ve como 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)

Documentación: ActionController::Base

• human_name es un sinónimo de human_attribute_name, que transforma nombre de atributos claves en un formato leible para el humano, como ‘Primer nombre’ en vez de ‘primer_nombre’

Documentación: ActiveRecord::Base

• h automáticamente ‘sale’ del código HTML. Uno de los problemas en permitirle al usuario que ingrese datos que luego son mostrados en la pantalla es que pueden accidentalmente (o maliciosamente) ingresar código que podria romper el sistema cuando es mostrado 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 renderizado como &lt;/table&gt; que es inofensivo. Rails hace esto realmente simple – solo agrega una ‘h’ como se muestra.

• confirm es un pará metro opcional m uy ú til para el helper link_to – genera una caja emergente de JavaScript que fuer za al usuario a confir mar la acción Destroy an tes de ejecutar el link:

Documentación: ActionView::Helpers::UrlHelper

La lógica de la página se aclara un poco. Ruby p uede u tilizar if como m o dificador: expresion if expresion-booleana evalua expresion solo si expresion-boolean es verdadera. @category_pages.current devuelve un objecto Página representando la página actual.

ActionController::Pagination::Paginator

y @category_pages.current.previous devuelve u n nuevo objeto Página representado la página an terior a la actual, o nulo si esta es la p ri mera página.

ActionController::Pagination::Paginator::Page

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

Página 15

Ilustración 3: Javascript emergente

Entonces, si hay u na página anterior a la cual navegar, este cont ructor m os t rará u n link; si no hay ninguna, el link es sup ri mido.

El código generado para 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 ScaffoldEl código generado por el scrip t Scaffold es perfecta men te u sable, y es robusto u na vez que haya agregado suficiente validación al m o delo de da tos. De todas for mas, si es to fuera todo el desar rollo necesario para aplicaciónes Rails, entonces los p rogra madores se quedarian sin t rabajo, que claramente no es algo bueno : - ) asi que realize mos algunas m o dificaciones:

El controlador

En la vista ‘List’, esperaria que los registros sean mostrados 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

Documentación: ActionController::Pagination

En esta aplicación, la pantalla show es innecesaria – todos los campos entran comodamente en una sola linea de la pantalla. Entonces, def show puede desaparecer, y vayamos directamente 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á tomado y mostrara en la siguiente pantalla – en este caso, la pantalla list. Por defecto, el script scaffold no muestra mensajes flash – cambiaremos esto en un minuto – vea abajo.

La Vista (View)

Mostrar mensajes Flash

Rails p rovee una técnica para pasar mensajes flash al u suario – ejem plo, un mensaje de ‘Actualización Exitosa’ que se m ues t ra en la siguiente pan talla y luego desaparece. Estos p ueden ser to mados fácilmente con u n pequeño cambio al Layout (agregarlo al Layout significa que apareceran en cualquier pan 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>

Documentació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 encabezado <h1>...</h1> de la plantilla al Layout para que aparezca sobre el mensaje flash. Como cada plantilla tendra un encabezado 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 renderizado.

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 formato 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 Documentación: class Time

Página 17

• págination_links crea una bar ra link HTML básica para u n paginador dado

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; deshacerme 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 nos lleva al final del Dia 2. Tene mos u n sis te ma funcionando para ma n tener n ues tra tabla de Categorias, y he mos em pezado a to mar cont rol del código scaffold que Rails ha generado.

Página 18

Día 3 con RailsAhora 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 opcionalmente puede tener un Nota, guardada 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.

La tabla ‘Items’

Definición MySQL de la tabla

Los cam pos en la tabla Items son los siguientes:

• done – 1 significa que el item de la lista ha sido finalizado 5

• priori ty – 1 (Alta p rioridad) a 5 (baja p rioridad)• descrip tion – texto libre indicando cual es la ta rea• d ue_date – indica cuando se deberia realizar la ta rea• category_id – un link a la Categoria a la que este item per tenece (‘id’ en la tabla de

Categorias)• note_id – u n link a una no ta opcional explicando es te item (‘id’ en la tabla de no tas)• private – 1 significa que el ite m de la lista esta clasificado como ‘Privado’

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

Como an tes, Rails p uede generar u n archivo de m o delo 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

Ilustración 4: Modelo de datos simplificado

Categoriesid

Notesid

Itemsidcategory_idnote_id

create app/models/item.rb create test/unit/item_test.rb create test/fixtures/items.yml

W:\ToDo>

que po de mos poblar con:

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.

Documentació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.

Documentación: ActiveRecord::Validations::ClassMethods

La tabla de ‘Notas’Esta tabla contiene u n solo cam po de texto libre pa ra con tener infor mación fut ura para un item de la lista de tareas en par ticular. Este da to po dria, por sup ues to, haber sido contenido en u n cam po de la tabla Items, de todas for mas, si lo hace de es ta for ma aprendera m ucho mas acerca de Rails : - )

Definición de la tabla MySQLTabla 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_notesend

pero necesita mos recordar agregar este enlace al m o delo de Items :

app\models\item.rb (fragmento)

class Item < ActiveRecord::Base belongs_to :note

Usar un Modelo para mantener Integridad Referencial

El código que esta mos a p u n to de desar rollar per mitira al u suario agregar una no ta a cualquier Item. Pero que ocurre cuando un usuario borra un Item que tiene un no ta asociada? Clara mente, necesita mos encontrar u na for ma de borrar el regist ro de la Nota ta mbién, de ot ra for ma nos quedan regist ros Notas “huerfanos”.

En la for ma de realizar el t rabajo Modelo / Vista / Controlador, es te código per tenece al m o delo. ¿Porqué? Bien, po dra ver m as tar de que pode mos borrar regist ros Items haciendo click en u n ícono de papelera de reciclaje en la pan talla “lista de tareas”, pero ta mbién po de mos borrar u n item haciendo click en Purgar items co m pletados. Colocando el código en el Modelo, sera ejecutado sin tener en cuenta de don de p rovenga la acción de eliminar.

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 :- )

Similarmente, 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) endend

Documentación: ActiveRecord::Callbacks

Página 21

Mas de ScaffoldGeneremos 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 podemos 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 derrumbe alrededor de sus ojos.

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

Nota: como m o dificamos la hoja de estilos ayer, ingrese “n” a la p regunta “overwrite (sobreescribir) p ublic / s tylesheets / scaffold.css? [Ynaq]”.

Mas acerca de Vistas

Crear un Layout para la Aplicación

Para ahora, se esta volviendo obvio de que todas mis plantillas tendran las mis mas p ri meras lineas de código, entonces tiene sen tido m over el código en co mun a un layout de la aplicación. Borre todos los archivos app\views\layouts\*.rhtml, y ree m placelos por un archivo comú n application.rhtml.

app\views\layouts\application.rhtml

<html><head> <title><%= @heading %></title> <%= stylesheet_link_tag 'todo' %><script language="JavaScript"><!-- Beginfunction 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 renombrado public/stylesheets/scaffold.css a todo.css para mantener una prolijidad, y también he jugado generalmente 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áticamente 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 que estoy inten tado conseguir es u na vista basada en un escritorio PalmPilot o PDA si milar. El p rod ucto final es m os t rado en la Ilus tración 5: La pan talla de ‘Lista de Tareas’8.

Algunos p u n tos:

• haciendo click en el encabezado de la colu mna ‘tilde’ (√) eliminara todos los items com pletados. (aquellos marcados con una tilde)

• La pan talla p uede ser ordenada haciendo click en los encabezados de las colu mnas ‘Pri’, ‘Descripción’, ‘Finalizar’, y ‘Categoria’

• los valores 0 / 1 para ‘Ter minado’ son convertidos en pequeños íconos tildes• ite ms que pasaron la fecha de finalización (due date) son coloreados en rojo y

m os t rados en negrita• la p resencia de u na nota asociada es m os t rada con el ícono ‘nota’• los valores 0 / 1 para ‘Privado’ son conver tidos en u n sí mbolo de candado• ite ms individuales p ueden ser edi tados o eliminados haciendo click en los íconos de la

derecha de la pan talla• la pan talla tiene un lindo efecto de ‘franjas’ • nuevos items p ueden ser agregados haciendo click en el botón ‘Nueva Tarea...’ en la

par te inferior de la pan talla• hay un botón enlace a las ‘Categorias’ del Día 2

La plantilla u tilizada para obtener esto es la siguiente:

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

Página 23

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

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 son creadas po r link_to_image, que por defecto espera encont rar la imagen en pub/images con una extensión .png; haciendo click en la imagen ejecutara un mé todo específico.

Agregando el pará metro :confirm genera u na ventana de dialogo emergente javascript como antes

Documentació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 controlador:

app\controllers\items_controller.rb (fragmento)

def purge_completed Item.destroy_all "done = 1" redirect_to :action => 'list' end

Item.destroy_all elimina todos los regist ros de la tabla Items don de el valor del cam po id done es 1, y luego devuelve la acción list.

Documentació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 ordenamiento por defecto en el método list , y creamos un nuevo método list_by_priority 9. Note también que necesitamos explicitamente render_action 'list', por defecto Rails intentará renderizar una plantilla llamada list_by_priority (que no existe :- )

Agregar el Helper

Los encabezados 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 mostrar 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) endend

Una vez que el helper ha sido enlazado por el controlador:

app\controllers\application.rb

class ApplicationController < ActionController::Base helper :Applicationend

esta disponible para todas las plantillas en la aplicación

Documentación: ActionView::Helpers

Usar botónes de navegación Javascript

onClick es u na técnica s tan dard Javascript para m a nejar acciónes de bo tónes co mo navegar a una n ueva página. De todas for mas, Rails reescribe las di recciones URLs, entonces necesitamos p reguntarle a Rails por la di reccion URL correcta a u tilizar. Dado un controlador y u na acción, url_for devolverá la URL.

Documentació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

Documentación: ActionView::Partials

Rails también pasa un número secuencial list_stripes_counter al Parcial. Esta es la clave para el formato alternado 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 Documentació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 Documentació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

También es fácil resaltar items específicos de da tos – por eje m plo, fechas en el pasado. list_stripes["due_date"] < Date.today ? '<td class="past_due">' : '<td>'

De nuevo, esto necesita ser igual a la ent rada .past_due en la hoja de estilos.

Manejar valores perdidos en una busqueda

Queremos que el sis te ma p ueda cubrirse en la si tuación don de el u suario borra u na Categoria que esta siendo usada por un item en la Lista de Tareas. En este caso, la Categoria deberia ser m os t rada co mo ‘sin archivar’:list_stripes.category ? list_stripes.category["category"] : 'Unfiled'

OK si ha llegado has ta aqui, deberia tener una pan talla ‘Lista de Tareas’ que se vea algo como la Ilust ración 5 La pantalla de ‘Lista de Tareas’ en la página 23.

La pantalla ‘Nueva Tarea’

Ahora sigue que pasa cuando uno p resiona el botón de ‘Nueva Tarea...’. De n uevo, todavía quedan algunos t rucos en el código.

La plantilla es mínima:

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

Ilustración 6 Pantalla Tarea Nueva

y el t rabajo real es realizado en el pa rcial, que p uede ser co m par tido 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

date_select genera un rudi men tario men u desplegable para ingresar la fecha:date_select "item", "due_date", :use_month_numbers => true

Documentación: ActionView::Helpers::DateHelper

Atrapar excepciones con Ruby

Desafor tunada men te, date_select feliz mente acep ta fechas co mo 31 de Febrero. Rails m uere cuando inten ta guardar es ta fecha en la base de datos. Una for ma de evitar esto es at rapar este intento de guar dar fallido usan do rescue, u n método de ma nejar excepciones de 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 Documentación: Exceptions, Catch, and Throw

Página 28

Crear una lista desplegable desde una tabla de busqueda

Este es ot ro eje m plo de Rails resolviendo u n p roblema de codificación diario de una for ma extremada mente econó mica. En es te ejem plo:options_from_collection_for_select @categories, "id", "category", @item.category_id

options_from_collection_for_select lee todos los regist ros en las categorias y los renderiza como <option value=”[value of id]”>[value of category]</option>. El regist ro que es igual a @item_category_id sera etiquetado co mo ‘ seleccionado’. Si es to no fuera suficiente, el código incluso u tiliza escapes h t ml para los da tos. Habil.

Documentación: ActionView::Helpers::FormOptionsHelper

Note que las cajas desplegables deben t raer los da tos de algun lugar – que significa u n agregado al con trolador:

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 una versión m as sim ple del caso anterior. Agregar u na lista de valores a una caja de selección en el código no es siem pre una buena idea – es m as fácil cambiar los da tos en la tabla que editar los valores en el código. De todas for mas, hay casos do nde es u na aproximación perfectamente valida, entonces en Rails haga: select "item","priority",[1,2,3,4,5]

Note ta mbién como indicar una valor po r defecto en la linea de código anterior.

Documentación: ActionView::Helpers::FormOptionsHelper

Crear una casilla de verificación

Otro requeri miento regular; o t ro helper en Rails:check_box "item","private"

Documentación: ActionView::Helpers::FormHelper

Toques finales

Modificar la hoja de estilos

Hasta es te p u n to, la pan talla de ‘Lista de Tareas’ deberia funcionar, y ta mbién deberia funcionar el botón ‘New To Do’. Para p roducir las pan tallas m os t radas aqui, ta mbién hice los siguientes cambios a la hoja de 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 res to del Dia 3 es la con tr ucción de la pan talla ‘Editar Tarea’, que es m uy si milar a ‘Nueva Tarea’. Estaba acos tu mbrado a m olestar me cuando los textos de secundaria decian: esto queda co mo un ejercicio fácil para el lector, ahora es genial po der hacer lo mis mo con us tedes 10.

Esto nos lleva al final del Dia 3 – y ahora la aplicación no se ve para nada como u n scaffold de Rails, pero bajo la superficie, todavía u tiliza mos un gran rango de her ra mientas de Rails pa ra hacer el desar rollo m as fácil.

10 Pero no como los autores de los textos de secundaria, yo si muestro la respuesta en el Dia 4 :- ) - vea app\views \i tems \edit.rhtml 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 queremos que el usuario invoque cualquiera de estas directamente. En cambio, si un item no tiene asociada una nota, queremos poder crear una nota haciendo click en el ícono de Nota en la pantalla de Edicion de tareas:

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

Primero que nada, veamos el código de la pan talla ‘Editar Tarea’. Note como los botónes de Notas cambian de acuerdo a si la Nota existe o no, y co mo el con trol es t ransferido al con trolador de 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

Ilustración 7: Crear una nota nueva desde la pantalla ‘Editar Tarea’

Ilustración 8: Editar o borrar una nota existente

<%= 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

Recuerde las reglas de integridad referencial que ya han sido creadas se aseguraran de

Página 32

que cuando u na no ta es eliminada, cualquier referencia a ella sera re movida del Item ta mbién (vea Integridad Referencial en la página 21).

La pantalla de ‘Nota Nueva’

Crear es un poco m as difícil. Quere mos hacer lo siguien te:

• guardar u na n ueva no ta en la tabla de Notas• encont rar el id de u n nuevo regist ro creado en la tabla de Notas• regist rar es te id en el campo no tes_id del regist ro asociado en la tabla de Items

Las variables de Sesión nos p roveen una for ma ú til de m an tener da tos ent re pan tallas – po de mos u tilizarlas aqui para guardar el Id del regist ro en la tabla de Notas.

Documentación: ActionController::Base

Guardar y traer Datos usando variables de Sesión

Primero que nada, cuando creamos un nuevo registro de Nota, pasamos el id del Item que estamos 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 acomodar 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 sistemaLos caminos finales de navegación a t raves del sis tema son m os t rados a continuación. Cualquier código scaffold redun dan te – ejem plo los archivos show.rhtml – p uende ser si m plemente eliminados. Esa es la belleza del código scaffold – no le cos to ningun esfuerzo crear el código en p ri mer lugar, y u na vez que sirvio su p roposi to, directamente lo p uede eliminar.

Página 34

Colocar una página de inicio para la AplicaciónComo paso final, necesitamos eliminar la pantalla por defecto 'Bienvenido a Rails' si el u suario ingresa en su navegador http://todo. Hay dos pasos:

• Agregar una página de inicio al archivo Routes:

config\routes.rb (fragmento)

map.connect '', :controller => 'items'

• reno mbrar public\index.html public\index.html.orig

Descargar una copia de esta aplicaciónSi quiere una copia de la aplicación ‘Lista de Tareas’ pa ra jugar, hay u n enlace en h t t p: / / r ails.ho melinux.org. Necesita

• usar Rails pa ra ar mar la es t ructura de directorios (vea Rails en la página 3)• descargar el archivo todo_app.zip en el nuevo directorio creado ToDo• desco m pri mir los archivos unzip -o todo_app.zip• reno mbrar public\index.html public\index.html.orig• si desea u sar la base de da tos de ejem plo, mysql -uroot -p < db/ToDo.sql

Y finalmenteEspero que encuent re es te docu mento ú til – siem pre me pone conten to recibir comentarios, buenos o m alos, a jp [email protected] .

Comenta rios de la versión en español a em manueln _at_ gmail.com

Feliz desar rollo con Rails!

Página 35

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

ListaTareas

NuevaTarea

EditarTarea

ListaCategorias

NuevaCategoria

EditarCategoria

NuevaNota

EditarNota

Apéndice – Cambios posterioresDespues de escribir ‘Cuatro Dias’, recibi m uchos comentarios que ayudaron a mejorar la calidad del docu mento. Una p regunta aparecio repetída mente - “como actualizo m as de un regist ro desde la mis ma pan talla” - en tonces aqui hay apén dice cubriendo estas Preguntas Frecuentes. No es el concepto mas fácil de do minar, y es u n area que esperaria que aparezcan mas “ayudantes” (helpers) en el fut uro.

Actualizaciones MultiplesEn la captura de pantalla de abajo, el usuario puede tildar /des 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.

View

Rails soporta actualizaciones multiples con otra convención de nombres, que es agregar el id del registro que se esta editando 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 generando. 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

Ilustración 10 : Actualizaciones multiples

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

Los pará metros pa ra check_box_tag son name, value = "1", checked = false, options = {};

para hidden_field_tag name, value = nil, options = {}

Documentación: ActionView::Helpers::FormTagHelper

Ade mas necesitamos u n bo tón Guardar (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 que re torna del cont rolador cuando se p resiona el botón “Guardar” es el siguien te hash:params: { :controller=>"items", :item=> { "6"=>{"done"=>"0"}, ... etc... "5"=>{"done"=>"1"} }, :action=>"updater"}

Estamos interesados en la pa r te de :item. Por ejem plo, la linea en negrita significa “el regist ro con el id = 6 tiene el valor del cam po done en 0”. Desde aqui, es un t rabajo bas tan te si mple el de actualizar la tabla de 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” en la variable item_id, y “done” = > “0” en attr.

Ruby Documentación: class Array

Este código funciona, pero si ve que es ta pasan do en development.log, vera que Rails esta t rayendo y actualizando cada regist ro, sea m o dificado o no. No solo esto esta creando actualizaciones innecesarias en la base de da tos, pero ta mbién significa que updated_on ta mbién estan siendo m o dificado, que no es en realidad lo que desea mos. Mucho mejor

Página 38

es solo actualizar si ‘done’ ha cambiado, pero esto significa tener que escribir m as 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 que necesita mos conver tir la cadena done a u n en tero usando to_i asi po de mos comparar los valores. Este es el tipo de te ma en el que fácilmente se falla – vale la pena chequear development.log de vez en cuando para asegura rse de que Rails esta haciendo lo que u no espera.

Consideraciones de la interfaz de usuario

Este código funciona, y p uede ser aplicado para hacer cualquier cam po de la pan talla edi table (otro ejercicio sim ple para el lector : - ). Si p resenta algunas p reguntas interesan tes acerca de que espera el usuario. Que pasa si el usuario cambia algunas de las cajas de verificación, y luego p resiona “Nueva Tarea...”, o si re - or dena la pan talla, sin p resionar “Guardar”? El sis te ma debería siem pre “Guardar” an tes de realizar cualquier o tra acción? Mas ejercicios para el lector...

Todavía para hacerEn la página 25 deje u n ejercicio con list_by_category para el lector. Fue m as fácil de lo que parecia – incluso, todavia estoy buscando u na for ma mas elegante en ‘Rails’ de ordenar po r cam po en u na tabla de busqueda. Ter miné con es te hor 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 una mejor solución, por favor haga melo saber. Dejo este código como ejem plo de que si todo falla, Rails no lo dejara t rabado pero le per mitira ordenar con este viejo código!

Disfru te el desar rollo con Rails!

Página 39

Indice de Terminos de Rails y Ruby usados en este DocumentoAaction_name .......................................................12Bbefore_type_cast ...............................................20belongs_to (pertenece a).................................20Ccheck_box ............................................................29check_box_tag ...................................................38confirm .........................................................15, 24content_columns ..............................................15content_for_layout ...........................................12created_at ..............................................................5created_on ......................................................5, 13current .................................................................15Ddate_select ..........................................................28destroy (destruir) ..............................................10destroy_all ..........................................................24development.log ....................................3, 10, 39Eend_form_tag .....................................................12error_messages_for .........................................13Ffind (encontrar) .................................................10find_all (encontrar todos) ..............................10Flash ......................................................................16Hh .............................................................................15helper (ayudante) ..............................................12hidden_field_tag ...............................................38HTML....................................................................15human_att ribute_name ...................................15human_name .....................................................15Iid ..............................................................................5Integridad Referencial .....................................21LLayout ...................................................................11link_to ..................................................................12link_to_image .....................................................24lock_versión ..........................................................5N

new (nuevo) ........................................................10Ooptions_from_collection_for_select ............29Ppaginate ...............................................................14págination_links ...............................................18Partial o Parcial .................................................11previous ...............................................................15Rredirect_to ...........................................................10render_collection_of_partials .......................26render_partial .............................................12, 25render_template ................................................10rescue ...................................................................28Ssave (guardar) ....................................................10select .....................................................................29start_form_tag ...................................................12strftime ................................................................17stylesheet_link_tag ...........................................12submit_tag ..........................................................12TTemplate o Plantilla .........................................11text_field .............................................................13Uupdate_attribute ...............................................38update_attributes (actualizar atributos) . . .10updated_at ............................................................5updated_on ....................................................5, 13url_for ..................................................................25Vvalidates_associated (validar asociaciones) ...20validates_format_of .........................................20validates_inclusion_of .....................................20validates_length_of .....................................7, 20validates_presence_of .....................................20validates_uniqueness_of ...................................7variable de sesión .............................................33..each ......................................................................38

Página 41