tutorial de ruby on rails

49
Tutorial de Ruby on Rails Ruby on Rails es la nueva generación en desarrollo de aplicaciones Web, y junto con AJAX está creando una revolución en la industria del desarrollo de software de web. Ruby y Rails Ruby es un lenguaje de programación interpretado y orientado a objetos. La filosofía de Ruby es don't repeat yourself (DRY) - no te repitas. La idea de ruby es que usted no necesita repetir lo que ya ha definido en otro lugar. Esto hace a ruby muy compacto. Rails es un armazón de librerías diseñado específicamente para crear aplicaciones de web. Como está hecho en ruby, es compatible con la filosofía de DRY. En vez de configuración, Rails prefiere convención y anotaciones. Esto proviene principalmente de las frustraciones con plataformas que obligan a uno a repetir en archivos de configuración XML una historia que ya se ha dicho en código. Acerca del Curso Este curso pretende proporcionar al usuario información suficiente para hacer aplicaciones de web profesionales utilizando Ruby on Rails. Está enfocado a personas que ya sepan algo de programación en otros lenguajes, lo cual quiere decir que durante el curso haré referencia a conceptos y librerías familiares a usuarios de otros lenguajes y productos. El curso se enfoca a crear una libreta de direcciones utilizando un servidor MySQL. Durante el curso también trato de enseñar conceptos relacionados como pruebas de unidad, metodologías ágiles y control de versiones. Optimizado para Firefox Si usted utiliza un browser de la familia Mozilla con soporte para XPath (como por ejemplo Firefox o Camino), usted podrá ver una lista de enlaces de referencia en cada capítulo, que es generada automáticamente. Esta lista de enlaces no est´ disponible en Internet Explorer. Si no tiene Firefox, puede instalar la version Firefox de Google haciendo click en el logo.

Upload: armando-beltran-g

Post on 03-Jul-2015

1.512 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Tutorial de Ruby on Rails

Tutorial de Ruby on Rails

Ruby on Rails es la nueva generacioacuten en desarrollo de aplicaciones Web y junto con AJAXestaacute creando una revolucioacuten en la industria del desarrollo de software de web

Ruby y Rails

Ruby es un lenguaje de programacioacuten interpretado y orientado a objetos La filosofiacutea deRuby es dont repeat yourself (DRY) - no te repitas La idea de ruby es que usted nonecesita repetir lo que ya ha definido en otro lugar Esto hace a ruby muy compacto

Rails es un armazoacuten de libreriacuteas disentildeado especiacuteficamente para crear aplicaciones de webComo estaacute hecho en ruby es compatible con la filosofiacutea de DRY En vez de configuracioacutenRails prefiere convencioacuten y anotaciones Esto proviene principalmente de las frustracionescon plataformas que obligan a uno a repetir en archivos de configuracioacuten XML una historiaque ya se ha dicho en coacutedigo

Acerca del Curso

Este curso pretende proporcionar al usuario informacioacuten suficiente para hacer aplicacionesde web profesionales utilizando Ruby on Rails Estaacute enfocado a personas que ya sepan algode programacioacuten en otros lenguajes lo cual quiere decir que durante el curso hareacutereferencia a conceptos y libreriacuteas familiares a usuarios de otros lenguajes y productos

El curso se enfoca a crear una libreta de direcciones utilizando un servidor MySQL Duranteel curso tambieacuten trato de ensentildear conceptos relacionados como pruebas de unidadmetodologiacuteas aacutegiles y control de versiones

Optimizado para Firefox

Si usted utiliza un browser de la familia Mozilla con soporte paraXPath (como por ejemplo Firefox o Camino) usted podraacute ver unalista de enlaces de referencia en cada capiacutetulo que es generadaautomaacuteticamente Esta lista de enlaces no estacute disponible enInternet Explorer

Si no tiene Firefox puede instalar la version Firefox de Googlehaciendo click en el logo

Contenido

Introduccioacuten2 Instalando Rails en su plataforma3 Nuestra primera aplicacioacuten - creando un esqueleto 4 Teoriacutea El Paradigma MVC5 Teoriacutea Pruebas de Unidad (Unit Tests)6 Configurando la base de datos7 Creando un Moacutedulo con Modelo Controlador y Vista8 Control de versiones con subversion9 Pruebas de Unidad en Rails

10 Teoriacutea de Objetos11 Mapeo de Objetos a Relaciones12 Modificando el Moacutedulo generado - Vistas13 Buen disentildeo con CSS14 Utilizando Helpers

1

1 Introduccioacuten

El internet ha madurado bastante desde los diacuteas de los start-ups Ruby on Rails y Web 20son el resultado de dicho proceso de maduracioacuten

Condiciones Econoacutemicas

Los antildeos 1997 hasta el 2001 fueron lo que se llamoacute el dot com bubble Los internet start-ups- compantildeiacuteas pequentildeas con fondos iniciales enormes proporcionados por compantildeiacuteas decapital riesgoso muy entusiastas - crearon una revolucioacuten basada en las expectativas de lanueva tecnologiacutea y aunque muchas compantildeiacuteas fueron muy exitosas y lograron convertirestos fondos iniciales en una compantildeiacutea redituable a largo plazo muchas otras dejaron deexistir en la caiacuteda de la burbuja del NASDAQ Como toda burbuja tecnoloacutegica esto es partede un ciclo econoacutemico

ldquoYou never leave a recession on the same technology that youentered itrdquo ldquoNunca sales de una recesioacuten con la misma tecnologiacutea con laque entraste rdquoChairman Emeritus of the BoardIntel Corporation

Algo interesante que suele ocurrir en las partes bajas de los ciclos econoacutemicos es que hayuna reorganizacioacuten y re-evaluacioacuten de las tecnologiacuteas disponibles (lo que funcionoacute y lo queno valioacute la pena) y durante estas re-evaluaciones nuevas tecnologiacuteas y nuevas maneras desolucionar problemas aparecen lo cual transforma cualitativamente la tecnologiacutea yrecomienza el ciclo econoacutemico

Cambios en Metodologiacutea

Durante estos antildeos de la recesioacuten en tecnologiacutea los procesos tambieacuten fueron re-evaluadosy las metodologiacuteas aacutegiles de desarrollo aparecieron con personajes como Martin Fowler deThoughtWorks y Dave Thomas de Pragmatic Programmers

Eacutestas metodologiacuteas ponen eacutenfasis en producir software de alta calidad en corto tiempomediante comnunicacioacuten abierta Hablaremos mucho maacutes de metodologiacuteas aacutegiles maacutestarde

Web 20

Este cambio de las expectativas de calidad en la tecnologiacutea de internet estaacute siendo llamadobien o mal Web 20 Hay muchas opiniones al respecto pero lo que todo mundo parececomprender es que la maacutes reciente generacioacuten de aplicaciones en la red es muy diferente alas anteriores Tim OReily trata de explicar Web 20 como una serie de principios ypraacutecticas que incluyen ciertos patrones de disentildeo dinaacutemicos como RSS tagscolaboracioacuten AJAX etceacutetera

Todos estos principios y cambios en expectativas de calidad tanto en el software producidocomo en la metodologiacutea para producirlo requieren de un dinamismo mucho mayor a lo que

era necesario antes con lenguajes compilados como Java Asiacute que maacutes y maacutesdesarrolladores sufriendo los problemas de la tecnologiacutea existente y bajo presion por lanueva metodologiacutea y expectativas comenzaron a buscar alternativas

Durante esta buacutesqueda de alternativas un programador Daneacutes llamado David HeinemeierHansson utilizoacute el lenguaje Ruby para crear una aplicacioacuten llamada Basecamp Las libreriacuteasreutilizables que salieron de este proyecto es lo que hoy conocemos como Ruby on Rails

2 Instalando Rails

Este capiacutetulo explica coacutemo puede usted instalar Rails en su plataforma de desarrollo

Rails es un proyecto de fuente abierta y como tal hay varias maneras de instalarlo yobtenerlo dependiendo de su plataforma y sus necesidades

En este artiacuteculo cubriremos dos maneras de instalar rails

Para principiantesPara usuarios avanzados y ambientes de prueba pre-produccioacuten y produccioacuten

Para Desarrolladores

Si usted es un desarrollador de software la manera maacutes sencilla de utilizar rails es medianteuna solucioacuten todo-en-uno que no afecte su ambiente actual

Windows

Si usted utiliza Windows puede instalar la plataforma Rails completa (incluyendo unaversion de mysql) utilizando proyecto Instant Rails Eacuteste proyecto incluye apache ruby railsy el servidor de mysql todo listo para ejecutarse

Macintosh

Si utiliza Macintosh OS X puede utilizar el proyecto Locomotive Locomotive incluye rubyrails y sqllite (en vez de un servidor de mysql) Si usted tiene un servidor mysql en otramaacutequina locomotive incluye las libreriacuteas de mysql para conectarse

Estos ambientes de desarrollo son adecuados para comenzar a escribir aplicaciones enRails en su propia maacutequina pero no son adecuados para ambientes multiusuario Asiacute queuna vez que usted tenga su programa listo para que otras personas lo utilizen (ya sea enmodo de prueba pre-produccioacuten o produccioacuten) necesitaraacute comprender como instalar unambiente de rails desde cero

Componentes de Rails

Para efectos de instalacioacuten Rails se puede dividir en los siguientes componentes

Lenguaje Ruby El lenguaje en el cual fueacute escrito RailsLas libreriacuteas de Rails Rails se compone de varias libreriacuteas escritas en rubyLa base de datos Una base de datos relacional basada en SQL es indispensable para un sistema dedesarrollo de aplicaciones web moderno La mayor parte de los ejemplos utilizan MySQL

Ruby

Ruby es un lenguaje de programacioacuten interpretado Ruby funciona con cualquier sistemaoperativo moderno pero se siente maacutes en casa en sistemas tipo Unix

La manera en que usted instale ruby depende mucho de su tipo de maacutequina y sus

>

necesidades Es recomendable que lea todo lo relevante a la plataforma que desee instalarantes de que haga una decisioacuten acerca de coacutemo instalarlo

Ruby en Unix Linux y Mac OS X

Si usted tiene una maacutequina que proviene de la familia Unix (incluyendo Mac OS X) esprobable que ya tenga Ruby incluido Rails requiere de ruby 182 o 184 (pero 183 nofunciona)

Para verificar su versioacuten de ruby ejecute el comando ruby -v Si su versioacuten es adecuadausted puede proceder a la seccioacuten de Gems

Si su versioacuten de ruby no es compatible con rails usted tiene dos opciones

1 Checar si su sistema operativo necesita actualizacioacuten y la versioacuten actualizada incluye un nuevo Ruby En la actualidad los sistemas Linux tienden a tener los maacutes nuevas instalaciones de Ruby en binario En sistemas Solaris algunos usuarios utilizan los paquetes binarios de CSW blastwave para mantenersus sistemas solaris actualizados sin tener que instalar un compilador en la maacutequinaEn Mac OS X depende de su versioacuten del sistema operativo El wiki de RubyGarden tiene informacioacutenacerca de como instalar los binarios

2 Instalar ruby en usrlocal ya sea en binario o compilado

Nota Muchos administradores de sistema Unix (en especial deLinux) prefieren instalar los sistemas de web compilando losarchivos fuente Esto permite el control absoluto de su ambientepero requiere de mayor conocimiento de su sistema asiacute como uncompilador

Si usted decide instalar un sistema ruby desde coacutedigo fuente baje el coacutedigo fuente del sitiooficial de Ruby (en Mac OS X tambieacuten necesita instalar las herramientas XCode quenormalmente vienen incluidos en sus discos del sistema operativo) y utilice la maneraestaacutendar de compilar programas en Unix

$ cd ruby-184-src

$ configure --prefix=usrlocal

$ make$ make install

Despueacutes de instalarlo antildeada el directorio usrlocalrubybin a su variable PATH

Recuerde Si su maacutequina ya incluiacutea ruby el directorio de su nuevacopia de Ruby debe estar antes de los demaacutes directorios en suvariable PATH

Ahora verifique que su instalacioacuten funciona ejecutando ruby -v yverificando la nueva versioacuten

Ruby en Windows

Como mencioneacute anteriormente ruby se encuentra maacutes en casa en un sistema Unix Elproblema principal de Windows es que eacuteste sistema operativo no viene con un compilador -los usuarios de Windows se sienten maacutes comodos con paquetes en binarios y con instalador

Si usted no tiene deseo de aprender a manejar un sistema Unix usted puede utilizar el OneClick Ruby Installer for Windows Este es un instalador que incluye ruby muchas libreriacuteas enbinario y el libro Programming Ruby The Pragmatic Programmers Guide en un archivo de

ayuda Una vez instalado sencillamente ejecute una liacutenea de comando y escriba ruby -vpara verificar su versioacuten

Pero si usted quisiera instalar un subsistema tipo Unix bajo Windows (o si usted estaacuteobligado a usar Windows por su trabajo pero prefiere usar Linux en casa) usted puedeinstalar Cygwin que es una recompilacioacuten de las utileriacuteas GNU bajo windows Durante lainstalacioacuten seleccione Ruby para que se encuentre incluido

Ruby Gems

RubyGems es un manejador de libreriacuteas de Ruby que hace muy sencillo instalar libreriacuteasGems esta a punto de convertirse en parte de ruby Pero si gems no estaacute incluido en suversioacuten de ruby (lo cual puede verificar ejecutando gem -v para ver la versioacuten de gemsinstalada) lo necesita instalar Como usted ya tiene ruby el procedimiento para instalarlo esel mismo para todos los sistemas operativos

cd rubygems

ruby setuprb gem -v

Ahora que tiene ruby gems puede proceder a instalar rails

MySQL

Ahora necesita una base de datos Si usted utiliza Unix es importante instalarla antes deinstalar el paquete mysql de gems porque las libreriacuteas de cliente de mysql son necesarias

Para instalar mysql baje la versioacuten para su plataforma del sitio de internet de MySQLcomUna vez que la instale puede proceder a instalar rails

Rails

Ahora siacute podemos instalar rails Para instalar rails ejecute lo siguiente

$ sudo gem install rails --include-dependencies$ sudo gem install mysql --with-mysql-dir=usrlocalmysql

El paraacutemetro with-mysql-dir soacutelo es necesario si su mysql no instala correctamente (porqueel compilador no encontroacute las libreriacuteas de mysql) Aseguacuterese de que el directorio queutilizaen el paraacutemetro sea el directorio donde instaloacute mysql

Finalmente ejecute el comando rails --version para verificar que su versioacuten de rails fueacuteinstalada correctamente

3 Nuestra primera aplicacioacuten

Creando un Esqueleto

Uno comienza con su aplicacioacuten de Rails creando un esqueleto Crear un esqueleto es muyfacil

$ rails direcciones

create

create appapis

create appcontrollers

create apphelpers

create appmodels

create appviewslayouts

create configenvironments

create components

create db

create doc

create lib

create log

create publicimages

create publicjavascripts

create publicstylesheets

create script

create testfixtures

create testfunctional

create testmocksdevelopment

create testmockstest

create testunit

Facil no Ahora veamos lo que creamos Para esto necesitamos ejecutar un servidor Railspuede ser configurado con apache y FastCGI Pero nuestro esqueleto tambien cuenta conun pequentildeo servidor web Asiacute que lo ejecutamos

$ cd direcciones

$ ruby scriptserver

=gt Rails application started on http00003000

=gt Ctrl-C to shutdown server call with --help for options

[2005-12-06 232744] INFO WEBrick 131[2005-12-06 232744] INFO ruby 182 (2004-12-25) [i386-

mswin32][2005-12-06 232745] INFO WEBrickHTTPServerstart pid=3972

port=3000

Note el puerto que el servidor nos ha dedicado 3000 Este es el puerto que vamos aaccesar utilizando nuestro navegador favorito La direccion es localhost o 127001 Asiacute queen nuestro navegador iremos a http1270013000 Si todo salioacute bien veremos unapantalla de felicitaciones con instrucciones para configurar Apache y pasos siguientes

Ahora que tenemos nuestra aplicacioacuten de rails lista podemos comenzar a ver como estaacutecompuesta nuestra nueva aplicacioacuten

Tu ambiente

Rails 11 tiene un enlace llamado About yourApplications environment que le permite verificarinformacioacuten acerca del ambiente Esta informacioacuten seencuentra en el URL rails_infoproperties

Anatomiacutea de una Aplicacioacuten Rails

Una aplicacioacuten rails se encuentra en el subdirectorio app y se compone de los siguientesdirectorios

apis - las libreriacuteas que su programa requiere fuera de Rails mismocontrollers - Los controladoreshelpers - Los helpersmodels - Los modelos Basicamente las clases que representan los datos que nuestra aplicacioacutenmanipularaacuteviews - Las vistas que son archivos rhtml (como JSP o ASP)

viewslayouts - Los disentildeos Cada controlador tiene su propio disentildeo donde se pondran las cabeceras ypies de paacuteginaconfig - Archivos de configuracioacuten La configuracioacuten de la base de datos se encuentra aquiacutescript - Utileriacuteas para generar coacutedigo y ejecutar el servidorpublic - La raiacutez del directorio virtual Cualquier contenido que usted encuentre aquiacute seraacute publicado en suaplicacioacuten directamente En una nueva aplicacioacuten usted puede encontrar las paacuteginas web para loserrores 404 y 500 las imaacutegenes javascripts estilos etceacuteteratest - Los archivos para las pruebas funcionales y de unidad

Llamando coacutedigo

Seguramente querremos que nuestro directorio tenga una pantalla principalConceptualmente llamaremos a esto el moacutedulo principal Asiacute que lo generamos

$ ruby scriptgenerate controller principal

exists appcontrollers

exists apphelpers

create appviewsprincipal

exists testfunctional

create appcontrollersprincipal_controllerrb

create testfunctionalprincipal_controller_testrb

create apphelpersprincipal_helperrb

Ahora puede usted visitar http1270013000principal para ver

Unknown actionNo action responded to index

El archivo que fue creado se llama controllersprincipal_controllerrb Vamos aponer nuestro coacutedigo ahiacute

class PrincipalController lt ApplicationController

def index

mensaje = Hola a todosltbrgt

[Pedro Pablo Juan]each do |nombre|

mensaje += y a +nombre+ tambienltbrgt

end

render text =gt mensaje

end

end

Cuando visitamos de nuevo vemos nuestro resultado

Hola a todosy a Pedro tambieny a Pablo tambieny a Juan tambien

Finalmente queremos que la raiacutez de esta aplicacioacuten sea tambieacuten nuestro controlador Asiacuteque eliminamos el indexhtml de bienvenida

$ rm publicindexhtml

Si vemos la paacutegina de nuevo ahora diraacute

Routing ErrorRecognition failed for

Esto es porque todaviacutea no le hemos dicho a la aplicacioacuten que nuestro controlador pordefecto es el principal Podemos hacer esto definiendo una ruta Asiacute que modificamos laconfiguracioacuten de rutas en el archivo configroutesrb

mapconnect controller =gt principal

Ahora cuando visitamos la paacutegina vemos el resultado de nuestro controlador principal

Si tiene dudas puede ver la peliacutecula

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 2: Tutorial de Ruby on Rails

Contenido

Introduccioacuten2 Instalando Rails en su plataforma3 Nuestra primera aplicacioacuten - creando un esqueleto 4 Teoriacutea El Paradigma MVC5 Teoriacutea Pruebas de Unidad (Unit Tests)6 Configurando la base de datos7 Creando un Moacutedulo con Modelo Controlador y Vista8 Control de versiones con subversion9 Pruebas de Unidad en Rails

10 Teoriacutea de Objetos11 Mapeo de Objetos a Relaciones12 Modificando el Moacutedulo generado - Vistas13 Buen disentildeo con CSS14 Utilizando Helpers

1

1 Introduccioacuten

El internet ha madurado bastante desde los diacuteas de los start-ups Ruby on Rails y Web 20son el resultado de dicho proceso de maduracioacuten

Condiciones Econoacutemicas

Los antildeos 1997 hasta el 2001 fueron lo que se llamoacute el dot com bubble Los internet start-ups- compantildeiacuteas pequentildeas con fondos iniciales enormes proporcionados por compantildeiacuteas decapital riesgoso muy entusiastas - crearon una revolucioacuten basada en las expectativas de lanueva tecnologiacutea y aunque muchas compantildeiacuteas fueron muy exitosas y lograron convertirestos fondos iniciales en una compantildeiacutea redituable a largo plazo muchas otras dejaron deexistir en la caiacuteda de la burbuja del NASDAQ Como toda burbuja tecnoloacutegica esto es partede un ciclo econoacutemico

ldquoYou never leave a recession on the same technology that youentered itrdquo ldquoNunca sales de una recesioacuten con la misma tecnologiacutea con laque entraste rdquoChairman Emeritus of the BoardIntel Corporation

Algo interesante que suele ocurrir en las partes bajas de los ciclos econoacutemicos es que hayuna reorganizacioacuten y re-evaluacioacuten de las tecnologiacuteas disponibles (lo que funcionoacute y lo queno valioacute la pena) y durante estas re-evaluaciones nuevas tecnologiacuteas y nuevas maneras desolucionar problemas aparecen lo cual transforma cualitativamente la tecnologiacutea yrecomienza el ciclo econoacutemico

Cambios en Metodologiacutea

Durante estos antildeos de la recesioacuten en tecnologiacutea los procesos tambieacuten fueron re-evaluadosy las metodologiacuteas aacutegiles de desarrollo aparecieron con personajes como Martin Fowler deThoughtWorks y Dave Thomas de Pragmatic Programmers

Eacutestas metodologiacuteas ponen eacutenfasis en producir software de alta calidad en corto tiempomediante comnunicacioacuten abierta Hablaremos mucho maacutes de metodologiacuteas aacutegiles maacutestarde

Web 20

Este cambio de las expectativas de calidad en la tecnologiacutea de internet estaacute siendo llamadobien o mal Web 20 Hay muchas opiniones al respecto pero lo que todo mundo parececomprender es que la maacutes reciente generacioacuten de aplicaciones en la red es muy diferente alas anteriores Tim OReily trata de explicar Web 20 como una serie de principios ypraacutecticas que incluyen ciertos patrones de disentildeo dinaacutemicos como RSS tagscolaboracioacuten AJAX etceacutetera

Todos estos principios y cambios en expectativas de calidad tanto en el software producidocomo en la metodologiacutea para producirlo requieren de un dinamismo mucho mayor a lo que

era necesario antes con lenguajes compilados como Java Asiacute que maacutes y maacutesdesarrolladores sufriendo los problemas de la tecnologiacutea existente y bajo presion por lanueva metodologiacutea y expectativas comenzaron a buscar alternativas

Durante esta buacutesqueda de alternativas un programador Daneacutes llamado David HeinemeierHansson utilizoacute el lenguaje Ruby para crear una aplicacioacuten llamada Basecamp Las libreriacuteasreutilizables que salieron de este proyecto es lo que hoy conocemos como Ruby on Rails

2 Instalando Rails

Este capiacutetulo explica coacutemo puede usted instalar Rails en su plataforma de desarrollo

Rails es un proyecto de fuente abierta y como tal hay varias maneras de instalarlo yobtenerlo dependiendo de su plataforma y sus necesidades

En este artiacuteculo cubriremos dos maneras de instalar rails

Para principiantesPara usuarios avanzados y ambientes de prueba pre-produccioacuten y produccioacuten

Para Desarrolladores

Si usted es un desarrollador de software la manera maacutes sencilla de utilizar rails es medianteuna solucioacuten todo-en-uno que no afecte su ambiente actual

Windows

Si usted utiliza Windows puede instalar la plataforma Rails completa (incluyendo unaversion de mysql) utilizando proyecto Instant Rails Eacuteste proyecto incluye apache ruby railsy el servidor de mysql todo listo para ejecutarse

Macintosh

Si utiliza Macintosh OS X puede utilizar el proyecto Locomotive Locomotive incluye rubyrails y sqllite (en vez de un servidor de mysql) Si usted tiene un servidor mysql en otramaacutequina locomotive incluye las libreriacuteas de mysql para conectarse

Estos ambientes de desarrollo son adecuados para comenzar a escribir aplicaciones enRails en su propia maacutequina pero no son adecuados para ambientes multiusuario Asiacute queuna vez que usted tenga su programa listo para que otras personas lo utilizen (ya sea enmodo de prueba pre-produccioacuten o produccioacuten) necesitaraacute comprender como instalar unambiente de rails desde cero

Componentes de Rails

Para efectos de instalacioacuten Rails se puede dividir en los siguientes componentes

Lenguaje Ruby El lenguaje en el cual fueacute escrito RailsLas libreriacuteas de Rails Rails se compone de varias libreriacuteas escritas en rubyLa base de datos Una base de datos relacional basada en SQL es indispensable para un sistema dedesarrollo de aplicaciones web moderno La mayor parte de los ejemplos utilizan MySQL

Ruby

Ruby es un lenguaje de programacioacuten interpretado Ruby funciona con cualquier sistemaoperativo moderno pero se siente maacutes en casa en sistemas tipo Unix

La manera en que usted instale ruby depende mucho de su tipo de maacutequina y sus

>

necesidades Es recomendable que lea todo lo relevante a la plataforma que desee instalarantes de que haga una decisioacuten acerca de coacutemo instalarlo

Ruby en Unix Linux y Mac OS X

Si usted tiene una maacutequina que proviene de la familia Unix (incluyendo Mac OS X) esprobable que ya tenga Ruby incluido Rails requiere de ruby 182 o 184 (pero 183 nofunciona)

Para verificar su versioacuten de ruby ejecute el comando ruby -v Si su versioacuten es adecuadausted puede proceder a la seccioacuten de Gems

Si su versioacuten de ruby no es compatible con rails usted tiene dos opciones

1 Checar si su sistema operativo necesita actualizacioacuten y la versioacuten actualizada incluye un nuevo Ruby En la actualidad los sistemas Linux tienden a tener los maacutes nuevas instalaciones de Ruby en binario En sistemas Solaris algunos usuarios utilizan los paquetes binarios de CSW blastwave para mantenersus sistemas solaris actualizados sin tener que instalar un compilador en la maacutequinaEn Mac OS X depende de su versioacuten del sistema operativo El wiki de RubyGarden tiene informacioacutenacerca de como instalar los binarios

2 Instalar ruby en usrlocal ya sea en binario o compilado

Nota Muchos administradores de sistema Unix (en especial deLinux) prefieren instalar los sistemas de web compilando losarchivos fuente Esto permite el control absoluto de su ambientepero requiere de mayor conocimiento de su sistema asiacute como uncompilador

Si usted decide instalar un sistema ruby desde coacutedigo fuente baje el coacutedigo fuente del sitiooficial de Ruby (en Mac OS X tambieacuten necesita instalar las herramientas XCode quenormalmente vienen incluidos en sus discos del sistema operativo) y utilice la maneraestaacutendar de compilar programas en Unix

$ cd ruby-184-src

$ configure --prefix=usrlocal

$ make$ make install

Despueacutes de instalarlo antildeada el directorio usrlocalrubybin a su variable PATH

Recuerde Si su maacutequina ya incluiacutea ruby el directorio de su nuevacopia de Ruby debe estar antes de los demaacutes directorios en suvariable PATH

Ahora verifique que su instalacioacuten funciona ejecutando ruby -v yverificando la nueva versioacuten

Ruby en Windows

Como mencioneacute anteriormente ruby se encuentra maacutes en casa en un sistema Unix Elproblema principal de Windows es que eacuteste sistema operativo no viene con un compilador -los usuarios de Windows se sienten maacutes comodos con paquetes en binarios y con instalador

Si usted no tiene deseo de aprender a manejar un sistema Unix usted puede utilizar el OneClick Ruby Installer for Windows Este es un instalador que incluye ruby muchas libreriacuteas enbinario y el libro Programming Ruby The Pragmatic Programmers Guide en un archivo de

ayuda Una vez instalado sencillamente ejecute una liacutenea de comando y escriba ruby -vpara verificar su versioacuten

Pero si usted quisiera instalar un subsistema tipo Unix bajo Windows (o si usted estaacuteobligado a usar Windows por su trabajo pero prefiere usar Linux en casa) usted puedeinstalar Cygwin que es una recompilacioacuten de las utileriacuteas GNU bajo windows Durante lainstalacioacuten seleccione Ruby para que se encuentre incluido

Ruby Gems

RubyGems es un manejador de libreriacuteas de Ruby que hace muy sencillo instalar libreriacuteasGems esta a punto de convertirse en parte de ruby Pero si gems no estaacute incluido en suversioacuten de ruby (lo cual puede verificar ejecutando gem -v para ver la versioacuten de gemsinstalada) lo necesita instalar Como usted ya tiene ruby el procedimiento para instalarlo esel mismo para todos los sistemas operativos

cd rubygems

ruby setuprb gem -v

Ahora que tiene ruby gems puede proceder a instalar rails

MySQL

Ahora necesita una base de datos Si usted utiliza Unix es importante instalarla antes deinstalar el paquete mysql de gems porque las libreriacuteas de cliente de mysql son necesarias

Para instalar mysql baje la versioacuten para su plataforma del sitio de internet de MySQLcomUna vez que la instale puede proceder a instalar rails

Rails

Ahora siacute podemos instalar rails Para instalar rails ejecute lo siguiente

$ sudo gem install rails --include-dependencies$ sudo gem install mysql --with-mysql-dir=usrlocalmysql

El paraacutemetro with-mysql-dir soacutelo es necesario si su mysql no instala correctamente (porqueel compilador no encontroacute las libreriacuteas de mysql) Aseguacuterese de que el directorio queutilizaen el paraacutemetro sea el directorio donde instaloacute mysql

Finalmente ejecute el comando rails --version para verificar que su versioacuten de rails fueacuteinstalada correctamente

3 Nuestra primera aplicacioacuten

Creando un Esqueleto

Uno comienza con su aplicacioacuten de Rails creando un esqueleto Crear un esqueleto es muyfacil

$ rails direcciones

create

create appapis

create appcontrollers

create apphelpers

create appmodels

create appviewslayouts

create configenvironments

create components

create db

create doc

create lib

create log

create publicimages

create publicjavascripts

create publicstylesheets

create script

create testfixtures

create testfunctional

create testmocksdevelopment

create testmockstest

create testunit

Facil no Ahora veamos lo que creamos Para esto necesitamos ejecutar un servidor Railspuede ser configurado con apache y FastCGI Pero nuestro esqueleto tambien cuenta conun pequentildeo servidor web Asiacute que lo ejecutamos

$ cd direcciones

$ ruby scriptserver

=gt Rails application started on http00003000

=gt Ctrl-C to shutdown server call with --help for options

[2005-12-06 232744] INFO WEBrick 131[2005-12-06 232744] INFO ruby 182 (2004-12-25) [i386-

mswin32][2005-12-06 232745] INFO WEBrickHTTPServerstart pid=3972

port=3000

Note el puerto que el servidor nos ha dedicado 3000 Este es el puerto que vamos aaccesar utilizando nuestro navegador favorito La direccion es localhost o 127001 Asiacute queen nuestro navegador iremos a http1270013000 Si todo salioacute bien veremos unapantalla de felicitaciones con instrucciones para configurar Apache y pasos siguientes

Ahora que tenemos nuestra aplicacioacuten de rails lista podemos comenzar a ver como estaacutecompuesta nuestra nueva aplicacioacuten

Tu ambiente

Rails 11 tiene un enlace llamado About yourApplications environment que le permite verificarinformacioacuten acerca del ambiente Esta informacioacuten seencuentra en el URL rails_infoproperties

Anatomiacutea de una Aplicacioacuten Rails

Una aplicacioacuten rails se encuentra en el subdirectorio app y se compone de los siguientesdirectorios

apis - las libreriacuteas que su programa requiere fuera de Rails mismocontrollers - Los controladoreshelpers - Los helpersmodels - Los modelos Basicamente las clases que representan los datos que nuestra aplicacioacutenmanipularaacuteviews - Las vistas que son archivos rhtml (como JSP o ASP)

viewslayouts - Los disentildeos Cada controlador tiene su propio disentildeo donde se pondran las cabeceras ypies de paacuteginaconfig - Archivos de configuracioacuten La configuracioacuten de la base de datos se encuentra aquiacutescript - Utileriacuteas para generar coacutedigo y ejecutar el servidorpublic - La raiacutez del directorio virtual Cualquier contenido que usted encuentre aquiacute seraacute publicado en suaplicacioacuten directamente En una nueva aplicacioacuten usted puede encontrar las paacuteginas web para loserrores 404 y 500 las imaacutegenes javascripts estilos etceacuteteratest - Los archivos para las pruebas funcionales y de unidad

Llamando coacutedigo

Seguramente querremos que nuestro directorio tenga una pantalla principalConceptualmente llamaremos a esto el moacutedulo principal Asiacute que lo generamos

$ ruby scriptgenerate controller principal

exists appcontrollers

exists apphelpers

create appviewsprincipal

exists testfunctional

create appcontrollersprincipal_controllerrb

create testfunctionalprincipal_controller_testrb

create apphelpersprincipal_helperrb

Ahora puede usted visitar http1270013000principal para ver

Unknown actionNo action responded to index

El archivo que fue creado se llama controllersprincipal_controllerrb Vamos aponer nuestro coacutedigo ahiacute

class PrincipalController lt ApplicationController

def index

mensaje = Hola a todosltbrgt

[Pedro Pablo Juan]each do |nombre|

mensaje += y a +nombre+ tambienltbrgt

end

render text =gt mensaje

end

end

Cuando visitamos de nuevo vemos nuestro resultado

Hola a todosy a Pedro tambieny a Pablo tambieny a Juan tambien

Finalmente queremos que la raiacutez de esta aplicacioacuten sea tambieacuten nuestro controlador Asiacuteque eliminamos el indexhtml de bienvenida

$ rm publicindexhtml

Si vemos la paacutegina de nuevo ahora diraacute

Routing ErrorRecognition failed for

Esto es porque todaviacutea no le hemos dicho a la aplicacioacuten que nuestro controlador pordefecto es el principal Podemos hacer esto definiendo una ruta Asiacute que modificamos laconfiguracioacuten de rutas en el archivo configroutesrb

mapconnect controller =gt principal

Ahora cuando visitamos la paacutegina vemos el resultado de nuestro controlador principal

Si tiene dudas puede ver la peliacutecula

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 3: Tutorial de Ruby on Rails

1 Introduccioacuten

El internet ha madurado bastante desde los diacuteas de los start-ups Ruby on Rails y Web 20son el resultado de dicho proceso de maduracioacuten

Condiciones Econoacutemicas

Los antildeos 1997 hasta el 2001 fueron lo que se llamoacute el dot com bubble Los internet start-ups- compantildeiacuteas pequentildeas con fondos iniciales enormes proporcionados por compantildeiacuteas decapital riesgoso muy entusiastas - crearon una revolucioacuten basada en las expectativas de lanueva tecnologiacutea y aunque muchas compantildeiacuteas fueron muy exitosas y lograron convertirestos fondos iniciales en una compantildeiacutea redituable a largo plazo muchas otras dejaron deexistir en la caiacuteda de la burbuja del NASDAQ Como toda burbuja tecnoloacutegica esto es partede un ciclo econoacutemico

ldquoYou never leave a recession on the same technology that youentered itrdquo ldquoNunca sales de una recesioacuten con la misma tecnologiacutea con laque entraste rdquoChairman Emeritus of the BoardIntel Corporation

Algo interesante que suele ocurrir en las partes bajas de los ciclos econoacutemicos es que hayuna reorganizacioacuten y re-evaluacioacuten de las tecnologiacuteas disponibles (lo que funcionoacute y lo queno valioacute la pena) y durante estas re-evaluaciones nuevas tecnologiacuteas y nuevas maneras desolucionar problemas aparecen lo cual transforma cualitativamente la tecnologiacutea yrecomienza el ciclo econoacutemico

Cambios en Metodologiacutea

Durante estos antildeos de la recesioacuten en tecnologiacutea los procesos tambieacuten fueron re-evaluadosy las metodologiacuteas aacutegiles de desarrollo aparecieron con personajes como Martin Fowler deThoughtWorks y Dave Thomas de Pragmatic Programmers

Eacutestas metodologiacuteas ponen eacutenfasis en producir software de alta calidad en corto tiempomediante comnunicacioacuten abierta Hablaremos mucho maacutes de metodologiacuteas aacutegiles maacutestarde

Web 20

Este cambio de las expectativas de calidad en la tecnologiacutea de internet estaacute siendo llamadobien o mal Web 20 Hay muchas opiniones al respecto pero lo que todo mundo parececomprender es que la maacutes reciente generacioacuten de aplicaciones en la red es muy diferente alas anteriores Tim OReily trata de explicar Web 20 como una serie de principios ypraacutecticas que incluyen ciertos patrones de disentildeo dinaacutemicos como RSS tagscolaboracioacuten AJAX etceacutetera

Todos estos principios y cambios en expectativas de calidad tanto en el software producidocomo en la metodologiacutea para producirlo requieren de un dinamismo mucho mayor a lo que

era necesario antes con lenguajes compilados como Java Asiacute que maacutes y maacutesdesarrolladores sufriendo los problemas de la tecnologiacutea existente y bajo presion por lanueva metodologiacutea y expectativas comenzaron a buscar alternativas

Durante esta buacutesqueda de alternativas un programador Daneacutes llamado David HeinemeierHansson utilizoacute el lenguaje Ruby para crear una aplicacioacuten llamada Basecamp Las libreriacuteasreutilizables que salieron de este proyecto es lo que hoy conocemos como Ruby on Rails

2 Instalando Rails

Este capiacutetulo explica coacutemo puede usted instalar Rails en su plataforma de desarrollo

Rails es un proyecto de fuente abierta y como tal hay varias maneras de instalarlo yobtenerlo dependiendo de su plataforma y sus necesidades

En este artiacuteculo cubriremos dos maneras de instalar rails

Para principiantesPara usuarios avanzados y ambientes de prueba pre-produccioacuten y produccioacuten

Para Desarrolladores

Si usted es un desarrollador de software la manera maacutes sencilla de utilizar rails es medianteuna solucioacuten todo-en-uno que no afecte su ambiente actual

Windows

Si usted utiliza Windows puede instalar la plataforma Rails completa (incluyendo unaversion de mysql) utilizando proyecto Instant Rails Eacuteste proyecto incluye apache ruby railsy el servidor de mysql todo listo para ejecutarse

Macintosh

Si utiliza Macintosh OS X puede utilizar el proyecto Locomotive Locomotive incluye rubyrails y sqllite (en vez de un servidor de mysql) Si usted tiene un servidor mysql en otramaacutequina locomotive incluye las libreriacuteas de mysql para conectarse

Estos ambientes de desarrollo son adecuados para comenzar a escribir aplicaciones enRails en su propia maacutequina pero no son adecuados para ambientes multiusuario Asiacute queuna vez que usted tenga su programa listo para que otras personas lo utilizen (ya sea enmodo de prueba pre-produccioacuten o produccioacuten) necesitaraacute comprender como instalar unambiente de rails desde cero

Componentes de Rails

Para efectos de instalacioacuten Rails se puede dividir en los siguientes componentes

Lenguaje Ruby El lenguaje en el cual fueacute escrito RailsLas libreriacuteas de Rails Rails se compone de varias libreriacuteas escritas en rubyLa base de datos Una base de datos relacional basada en SQL es indispensable para un sistema dedesarrollo de aplicaciones web moderno La mayor parte de los ejemplos utilizan MySQL

Ruby

Ruby es un lenguaje de programacioacuten interpretado Ruby funciona con cualquier sistemaoperativo moderno pero se siente maacutes en casa en sistemas tipo Unix

La manera en que usted instale ruby depende mucho de su tipo de maacutequina y sus

>

necesidades Es recomendable que lea todo lo relevante a la plataforma que desee instalarantes de que haga una decisioacuten acerca de coacutemo instalarlo

Ruby en Unix Linux y Mac OS X

Si usted tiene una maacutequina que proviene de la familia Unix (incluyendo Mac OS X) esprobable que ya tenga Ruby incluido Rails requiere de ruby 182 o 184 (pero 183 nofunciona)

Para verificar su versioacuten de ruby ejecute el comando ruby -v Si su versioacuten es adecuadausted puede proceder a la seccioacuten de Gems

Si su versioacuten de ruby no es compatible con rails usted tiene dos opciones

1 Checar si su sistema operativo necesita actualizacioacuten y la versioacuten actualizada incluye un nuevo Ruby En la actualidad los sistemas Linux tienden a tener los maacutes nuevas instalaciones de Ruby en binario En sistemas Solaris algunos usuarios utilizan los paquetes binarios de CSW blastwave para mantenersus sistemas solaris actualizados sin tener que instalar un compilador en la maacutequinaEn Mac OS X depende de su versioacuten del sistema operativo El wiki de RubyGarden tiene informacioacutenacerca de como instalar los binarios

2 Instalar ruby en usrlocal ya sea en binario o compilado

Nota Muchos administradores de sistema Unix (en especial deLinux) prefieren instalar los sistemas de web compilando losarchivos fuente Esto permite el control absoluto de su ambientepero requiere de mayor conocimiento de su sistema asiacute como uncompilador

Si usted decide instalar un sistema ruby desde coacutedigo fuente baje el coacutedigo fuente del sitiooficial de Ruby (en Mac OS X tambieacuten necesita instalar las herramientas XCode quenormalmente vienen incluidos en sus discos del sistema operativo) y utilice la maneraestaacutendar de compilar programas en Unix

$ cd ruby-184-src

$ configure --prefix=usrlocal

$ make$ make install

Despueacutes de instalarlo antildeada el directorio usrlocalrubybin a su variable PATH

Recuerde Si su maacutequina ya incluiacutea ruby el directorio de su nuevacopia de Ruby debe estar antes de los demaacutes directorios en suvariable PATH

Ahora verifique que su instalacioacuten funciona ejecutando ruby -v yverificando la nueva versioacuten

Ruby en Windows

Como mencioneacute anteriormente ruby se encuentra maacutes en casa en un sistema Unix Elproblema principal de Windows es que eacuteste sistema operativo no viene con un compilador -los usuarios de Windows se sienten maacutes comodos con paquetes en binarios y con instalador

Si usted no tiene deseo de aprender a manejar un sistema Unix usted puede utilizar el OneClick Ruby Installer for Windows Este es un instalador que incluye ruby muchas libreriacuteas enbinario y el libro Programming Ruby The Pragmatic Programmers Guide en un archivo de

ayuda Una vez instalado sencillamente ejecute una liacutenea de comando y escriba ruby -vpara verificar su versioacuten

Pero si usted quisiera instalar un subsistema tipo Unix bajo Windows (o si usted estaacuteobligado a usar Windows por su trabajo pero prefiere usar Linux en casa) usted puedeinstalar Cygwin que es una recompilacioacuten de las utileriacuteas GNU bajo windows Durante lainstalacioacuten seleccione Ruby para que se encuentre incluido

Ruby Gems

RubyGems es un manejador de libreriacuteas de Ruby que hace muy sencillo instalar libreriacuteasGems esta a punto de convertirse en parte de ruby Pero si gems no estaacute incluido en suversioacuten de ruby (lo cual puede verificar ejecutando gem -v para ver la versioacuten de gemsinstalada) lo necesita instalar Como usted ya tiene ruby el procedimiento para instalarlo esel mismo para todos los sistemas operativos

cd rubygems

ruby setuprb gem -v

Ahora que tiene ruby gems puede proceder a instalar rails

MySQL

Ahora necesita una base de datos Si usted utiliza Unix es importante instalarla antes deinstalar el paquete mysql de gems porque las libreriacuteas de cliente de mysql son necesarias

Para instalar mysql baje la versioacuten para su plataforma del sitio de internet de MySQLcomUna vez que la instale puede proceder a instalar rails

Rails

Ahora siacute podemos instalar rails Para instalar rails ejecute lo siguiente

$ sudo gem install rails --include-dependencies$ sudo gem install mysql --with-mysql-dir=usrlocalmysql

El paraacutemetro with-mysql-dir soacutelo es necesario si su mysql no instala correctamente (porqueel compilador no encontroacute las libreriacuteas de mysql) Aseguacuterese de que el directorio queutilizaen el paraacutemetro sea el directorio donde instaloacute mysql

Finalmente ejecute el comando rails --version para verificar que su versioacuten de rails fueacuteinstalada correctamente

3 Nuestra primera aplicacioacuten

Creando un Esqueleto

Uno comienza con su aplicacioacuten de Rails creando un esqueleto Crear un esqueleto es muyfacil

$ rails direcciones

create

create appapis

create appcontrollers

create apphelpers

create appmodels

create appviewslayouts

create configenvironments

create components

create db

create doc

create lib

create log

create publicimages

create publicjavascripts

create publicstylesheets

create script

create testfixtures

create testfunctional

create testmocksdevelopment

create testmockstest

create testunit

Facil no Ahora veamos lo que creamos Para esto necesitamos ejecutar un servidor Railspuede ser configurado con apache y FastCGI Pero nuestro esqueleto tambien cuenta conun pequentildeo servidor web Asiacute que lo ejecutamos

$ cd direcciones

$ ruby scriptserver

=gt Rails application started on http00003000

=gt Ctrl-C to shutdown server call with --help for options

[2005-12-06 232744] INFO WEBrick 131[2005-12-06 232744] INFO ruby 182 (2004-12-25) [i386-

mswin32][2005-12-06 232745] INFO WEBrickHTTPServerstart pid=3972

port=3000

Note el puerto que el servidor nos ha dedicado 3000 Este es el puerto que vamos aaccesar utilizando nuestro navegador favorito La direccion es localhost o 127001 Asiacute queen nuestro navegador iremos a http1270013000 Si todo salioacute bien veremos unapantalla de felicitaciones con instrucciones para configurar Apache y pasos siguientes

Ahora que tenemos nuestra aplicacioacuten de rails lista podemos comenzar a ver como estaacutecompuesta nuestra nueva aplicacioacuten

Tu ambiente

Rails 11 tiene un enlace llamado About yourApplications environment que le permite verificarinformacioacuten acerca del ambiente Esta informacioacuten seencuentra en el URL rails_infoproperties

Anatomiacutea de una Aplicacioacuten Rails

Una aplicacioacuten rails se encuentra en el subdirectorio app y se compone de los siguientesdirectorios

apis - las libreriacuteas que su programa requiere fuera de Rails mismocontrollers - Los controladoreshelpers - Los helpersmodels - Los modelos Basicamente las clases que representan los datos que nuestra aplicacioacutenmanipularaacuteviews - Las vistas que son archivos rhtml (como JSP o ASP)

viewslayouts - Los disentildeos Cada controlador tiene su propio disentildeo donde se pondran las cabeceras ypies de paacuteginaconfig - Archivos de configuracioacuten La configuracioacuten de la base de datos se encuentra aquiacutescript - Utileriacuteas para generar coacutedigo y ejecutar el servidorpublic - La raiacutez del directorio virtual Cualquier contenido que usted encuentre aquiacute seraacute publicado en suaplicacioacuten directamente En una nueva aplicacioacuten usted puede encontrar las paacuteginas web para loserrores 404 y 500 las imaacutegenes javascripts estilos etceacuteteratest - Los archivos para las pruebas funcionales y de unidad

Llamando coacutedigo

Seguramente querremos que nuestro directorio tenga una pantalla principalConceptualmente llamaremos a esto el moacutedulo principal Asiacute que lo generamos

$ ruby scriptgenerate controller principal

exists appcontrollers

exists apphelpers

create appviewsprincipal

exists testfunctional

create appcontrollersprincipal_controllerrb

create testfunctionalprincipal_controller_testrb

create apphelpersprincipal_helperrb

Ahora puede usted visitar http1270013000principal para ver

Unknown actionNo action responded to index

El archivo que fue creado se llama controllersprincipal_controllerrb Vamos aponer nuestro coacutedigo ahiacute

class PrincipalController lt ApplicationController

def index

mensaje = Hola a todosltbrgt

[Pedro Pablo Juan]each do |nombre|

mensaje += y a +nombre+ tambienltbrgt

end

render text =gt mensaje

end

end

Cuando visitamos de nuevo vemos nuestro resultado

Hola a todosy a Pedro tambieny a Pablo tambieny a Juan tambien

Finalmente queremos que la raiacutez de esta aplicacioacuten sea tambieacuten nuestro controlador Asiacuteque eliminamos el indexhtml de bienvenida

$ rm publicindexhtml

Si vemos la paacutegina de nuevo ahora diraacute

Routing ErrorRecognition failed for

Esto es porque todaviacutea no le hemos dicho a la aplicacioacuten que nuestro controlador pordefecto es el principal Podemos hacer esto definiendo una ruta Asiacute que modificamos laconfiguracioacuten de rutas en el archivo configroutesrb

mapconnect controller =gt principal

Ahora cuando visitamos la paacutegina vemos el resultado de nuestro controlador principal

Si tiene dudas puede ver la peliacutecula

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 4: Tutorial de Ruby on Rails

era necesario antes con lenguajes compilados como Java Asiacute que maacutes y maacutesdesarrolladores sufriendo los problemas de la tecnologiacutea existente y bajo presion por lanueva metodologiacutea y expectativas comenzaron a buscar alternativas

Durante esta buacutesqueda de alternativas un programador Daneacutes llamado David HeinemeierHansson utilizoacute el lenguaje Ruby para crear una aplicacioacuten llamada Basecamp Las libreriacuteasreutilizables que salieron de este proyecto es lo que hoy conocemos como Ruby on Rails

2 Instalando Rails

Este capiacutetulo explica coacutemo puede usted instalar Rails en su plataforma de desarrollo

Rails es un proyecto de fuente abierta y como tal hay varias maneras de instalarlo yobtenerlo dependiendo de su plataforma y sus necesidades

En este artiacuteculo cubriremos dos maneras de instalar rails

Para principiantesPara usuarios avanzados y ambientes de prueba pre-produccioacuten y produccioacuten

Para Desarrolladores

Si usted es un desarrollador de software la manera maacutes sencilla de utilizar rails es medianteuna solucioacuten todo-en-uno que no afecte su ambiente actual

Windows

Si usted utiliza Windows puede instalar la plataforma Rails completa (incluyendo unaversion de mysql) utilizando proyecto Instant Rails Eacuteste proyecto incluye apache ruby railsy el servidor de mysql todo listo para ejecutarse

Macintosh

Si utiliza Macintosh OS X puede utilizar el proyecto Locomotive Locomotive incluye rubyrails y sqllite (en vez de un servidor de mysql) Si usted tiene un servidor mysql en otramaacutequina locomotive incluye las libreriacuteas de mysql para conectarse

Estos ambientes de desarrollo son adecuados para comenzar a escribir aplicaciones enRails en su propia maacutequina pero no son adecuados para ambientes multiusuario Asiacute queuna vez que usted tenga su programa listo para que otras personas lo utilizen (ya sea enmodo de prueba pre-produccioacuten o produccioacuten) necesitaraacute comprender como instalar unambiente de rails desde cero

Componentes de Rails

Para efectos de instalacioacuten Rails se puede dividir en los siguientes componentes

Lenguaje Ruby El lenguaje en el cual fueacute escrito RailsLas libreriacuteas de Rails Rails se compone de varias libreriacuteas escritas en rubyLa base de datos Una base de datos relacional basada en SQL es indispensable para un sistema dedesarrollo de aplicaciones web moderno La mayor parte de los ejemplos utilizan MySQL

Ruby

Ruby es un lenguaje de programacioacuten interpretado Ruby funciona con cualquier sistemaoperativo moderno pero se siente maacutes en casa en sistemas tipo Unix

La manera en que usted instale ruby depende mucho de su tipo de maacutequina y sus

>

necesidades Es recomendable que lea todo lo relevante a la plataforma que desee instalarantes de que haga una decisioacuten acerca de coacutemo instalarlo

Ruby en Unix Linux y Mac OS X

Si usted tiene una maacutequina que proviene de la familia Unix (incluyendo Mac OS X) esprobable que ya tenga Ruby incluido Rails requiere de ruby 182 o 184 (pero 183 nofunciona)

Para verificar su versioacuten de ruby ejecute el comando ruby -v Si su versioacuten es adecuadausted puede proceder a la seccioacuten de Gems

Si su versioacuten de ruby no es compatible con rails usted tiene dos opciones

1 Checar si su sistema operativo necesita actualizacioacuten y la versioacuten actualizada incluye un nuevo Ruby En la actualidad los sistemas Linux tienden a tener los maacutes nuevas instalaciones de Ruby en binario En sistemas Solaris algunos usuarios utilizan los paquetes binarios de CSW blastwave para mantenersus sistemas solaris actualizados sin tener que instalar un compilador en la maacutequinaEn Mac OS X depende de su versioacuten del sistema operativo El wiki de RubyGarden tiene informacioacutenacerca de como instalar los binarios

2 Instalar ruby en usrlocal ya sea en binario o compilado

Nota Muchos administradores de sistema Unix (en especial deLinux) prefieren instalar los sistemas de web compilando losarchivos fuente Esto permite el control absoluto de su ambientepero requiere de mayor conocimiento de su sistema asiacute como uncompilador

Si usted decide instalar un sistema ruby desde coacutedigo fuente baje el coacutedigo fuente del sitiooficial de Ruby (en Mac OS X tambieacuten necesita instalar las herramientas XCode quenormalmente vienen incluidos en sus discos del sistema operativo) y utilice la maneraestaacutendar de compilar programas en Unix

$ cd ruby-184-src

$ configure --prefix=usrlocal

$ make$ make install

Despueacutes de instalarlo antildeada el directorio usrlocalrubybin a su variable PATH

Recuerde Si su maacutequina ya incluiacutea ruby el directorio de su nuevacopia de Ruby debe estar antes de los demaacutes directorios en suvariable PATH

Ahora verifique que su instalacioacuten funciona ejecutando ruby -v yverificando la nueva versioacuten

Ruby en Windows

Como mencioneacute anteriormente ruby se encuentra maacutes en casa en un sistema Unix Elproblema principal de Windows es que eacuteste sistema operativo no viene con un compilador -los usuarios de Windows se sienten maacutes comodos con paquetes en binarios y con instalador

Si usted no tiene deseo de aprender a manejar un sistema Unix usted puede utilizar el OneClick Ruby Installer for Windows Este es un instalador que incluye ruby muchas libreriacuteas enbinario y el libro Programming Ruby The Pragmatic Programmers Guide en un archivo de

ayuda Una vez instalado sencillamente ejecute una liacutenea de comando y escriba ruby -vpara verificar su versioacuten

Pero si usted quisiera instalar un subsistema tipo Unix bajo Windows (o si usted estaacuteobligado a usar Windows por su trabajo pero prefiere usar Linux en casa) usted puedeinstalar Cygwin que es una recompilacioacuten de las utileriacuteas GNU bajo windows Durante lainstalacioacuten seleccione Ruby para que se encuentre incluido

Ruby Gems

RubyGems es un manejador de libreriacuteas de Ruby que hace muy sencillo instalar libreriacuteasGems esta a punto de convertirse en parte de ruby Pero si gems no estaacute incluido en suversioacuten de ruby (lo cual puede verificar ejecutando gem -v para ver la versioacuten de gemsinstalada) lo necesita instalar Como usted ya tiene ruby el procedimiento para instalarlo esel mismo para todos los sistemas operativos

cd rubygems

ruby setuprb gem -v

Ahora que tiene ruby gems puede proceder a instalar rails

MySQL

Ahora necesita una base de datos Si usted utiliza Unix es importante instalarla antes deinstalar el paquete mysql de gems porque las libreriacuteas de cliente de mysql son necesarias

Para instalar mysql baje la versioacuten para su plataforma del sitio de internet de MySQLcomUna vez que la instale puede proceder a instalar rails

Rails

Ahora siacute podemos instalar rails Para instalar rails ejecute lo siguiente

$ sudo gem install rails --include-dependencies$ sudo gem install mysql --with-mysql-dir=usrlocalmysql

El paraacutemetro with-mysql-dir soacutelo es necesario si su mysql no instala correctamente (porqueel compilador no encontroacute las libreriacuteas de mysql) Aseguacuterese de que el directorio queutilizaen el paraacutemetro sea el directorio donde instaloacute mysql

Finalmente ejecute el comando rails --version para verificar que su versioacuten de rails fueacuteinstalada correctamente

3 Nuestra primera aplicacioacuten

Creando un Esqueleto

Uno comienza con su aplicacioacuten de Rails creando un esqueleto Crear un esqueleto es muyfacil

$ rails direcciones

create

create appapis

create appcontrollers

create apphelpers

create appmodels

create appviewslayouts

create configenvironments

create components

create db

create doc

create lib

create log

create publicimages

create publicjavascripts

create publicstylesheets

create script

create testfixtures

create testfunctional

create testmocksdevelopment

create testmockstest

create testunit

Facil no Ahora veamos lo que creamos Para esto necesitamos ejecutar un servidor Railspuede ser configurado con apache y FastCGI Pero nuestro esqueleto tambien cuenta conun pequentildeo servidor web Asiacute que lo ejecutamos

$ cd direcciones

$ ruby scriptserver

=gt Rails application started on http00003000

=gt Ctrl-C to shutdown server call with --help for options

[2005-12-06 232744] INFO WEBrick 131[2005-12-06 232744] INFO ruby 182 (2004-12-25) [i386-

mswin32][2005-12-06 232745] INFO WEBrickHTTPServerstart pid=3972

port=3000

Note el puerto que el servidor nos ha dedicado 3000 Este es el puerto que vamos aaccesar utilizando nuestro navegador favorito La direccion es localhost o 127001 Asiacute queen nuestro navegador iremos a http1270013000 Si todo salioacute bien veremos unapantalla de felicitaciones con instrucciones para configurar Apache y pasos siguientes

Ahora que tenemos nuestra aplicacioacuten de rails lista podemos comenzar a ver como estaacutecompuesta nuestra nueva aplicacioacuten

Tu ambiente

Rails 11 tiene un enlace llamado About yourApplications environment que le permite verificarinformacioacuten acerca del ambiente Esta informacioacuten seencuentra en el URL rails_infoproperties

Anatomiacutea de una Aplicacioacuten Rails

Una aplicacioacuten rails se encuentra en el subdirectorio app y se compone de los siguientesdirectorios

apis - las libreriacuteas que su programa requiere fuera de Rails mismocontrollers - Los controladoreshelpers - Los helpersmodels - Los modelos Basicamente las clases que representan los datos que nuestra aplicacioacutenmanipularaacuteviews - Las vistas que son archivos rhtml (como JSP o ASP)

viewslayouts - Los disentildeos Cada controlador tiene su propio disentildeo donde se pondran las cabeceras ypies de paacuteginaconfig - Archivos de configuracioacuten La configuracioacuten de la base de datos se encuentra aquiacutescript - Utileriacuteas para generar coacutedigo y ejecutar el servidorpublic - La raiacutez del directorio virtual Cualquier contenido que usted encuentre aquiacute seraacute publicado en suaplicacioacuten directamente En una nueva aplicacioacuten usted puede encontrar las paacuteginas web para loserrores 404 y 500 las imaacutegenes javascripts estilos etceacuteteratest - Los archivos para las pruebas funcionales y de unidad

Llamando coacutedigo

Seguramente querremos que nuestro directorio tenga una pantalla principalConceptualmente llamaremos a esto el moacutedulo principal Asiacute que lo generamos

$ ruby scriptgenerate controller principal

exists appcontrollers

exists apphelpers

create appviewsprincipal

exists testfunctional

create appcontrollersprincipal_controllerrb

create testfunctionalprincipal_controller_testrb

create apphelpersprincipal_helperrb

Ahora puede usted visitar http1270013000principal para ver

Unknown actionNo action responded to index

El archivo que fue creado se llama controllersprincipal_controllerrb Vamos aponer nuestro coacutedigo ahiacute

class PrincipalController lt ApplicationController

def index

mensaje = Hola a todosltbrgt

[Pedro Pablo Juan]each do |nombre|

mensaje += y a +nombre+ tambienltbrgt

end

render text =gt mensaje

end

end

Cuando visitamos de nuevo vemos nuestro resultado

Hola a todosy a Pedro tambieny a Pablo tambieny a Juan tambien

Finalmente queremos que la raiacutez de esta aplicacioacuten sea tambieacuten nuestro controlador Asiacuteque eliminamos el indexhtml de bienvenida

$ rm publicindexhtml

Si vemos la paacutegina de nuevo ahora diraacute

Routing ErrorRecognition failed for

Esto es porque todaviacutea no le hemos dicho a la aplicacioacuten que nuestro controlador pordefecto es el principal Podemos hacer esto definiendo una ruta Asiacute que modificamos laconfiguracioacuten de rutas en el archivo configroutesrb

mapconnect controller =gt principal

Ahora cuando visitamos la paacutegina vemos el resultado de nuestro controlador principal

Si tiene dudas puede ver la peliacutecula

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 5: Tutorial de Ruby on Rails

2 Instalando Rails

Este capiacutetulo explica coacutemo puede usted instalar Rails en su plataforma de desarrollo

Rails es un proyecto de fuente abierta y como tal hay varias maneras de instalarlo yobtenerlo dependiendo de su plataforma y sus necesidades

En este artiacuteculo cubriremos dos maneras de instalar rails

Para principiantesPara usuarios avanzados y ambientes de prueba pre-produccioacuten y produccioacuten

Para Desarrolladores

Si usted es un desarrollador de software la manera maacutes sencilla de utilizar rails es medianteuna solucioacuten todo-en-uno que no afecte su ambiente actual

Windows

Si usted utiliza Windows puede instalar la plataforma Rails completa (incluyendo unaversion de mysql) utilizando proyecto Instant Rails Eacuteste proyecto incluye apache ruby railsy el servidor de mysql todo listo para ejecutarse

Macintosh

Si utiliza Macintosh OS X puede utilizar el proyecto Locomotive Locomotive incluye rubyrails y sqllite (en vez de un servidor de mysql) Si usted tiene un servidor mysql en otramaacutequina locomotive incluye las libreriacuteas de mysql para conectarse

Estos ambientes de desarrollo son adecuados para comenzar a escribir aplicaciones enRails en su propia maacutequina pero no son adecuados para ambientes multiusuario Asiacute queuna vez que usted tenga su programa listo para que otras personas lo utilizen (ya sea enmodo de prueba pre-produccioacuten o produccioacuten) necesitaraacute comprender como instalar unambiente de rails desde cero

Componentes de Rails

Para efectos de instalacioacuten Rails se puede dividir en los siguientes componentes

Lenguaje Ruby El lenguaje en el cual fueacute escrito RailsLas libreriacuteas de Rails Rails se compone de varias libreriacuteas escritas en rubyLa base de datos Una base de datos relacional basada en SQL es indispensable para un sistema dedesarrollo de aplicaciones web moderno La mayor parte de los ejemplos utilizan MySQL

Ruby

Ruby es un lenguaje de programacioacuten interpretado Ruby funciona con cualquier sistemaoperativo moderno pero se siente maacutes en casa en sistemas tipo Unix

La manera en que usted instale ruby depende mucho de su tipo de maacutequina y sus

>

necesidades Es recomendable que lea todo lo relevante a la plataforma que desee instalarantes de que haga una decisioacuten acerca de coacutemo instalarlo

Ruby en Unix Linux y Mac OS X

Si usted tiene una maacutequina que proviene de la familia Unix (incluyendo Mac OS X) esprobable que ya tenga Ruby incluido Rails requiere de ruby 182 o 184 (pero 183 nofunciona)

Para verificar su versioacuten de ruby ejecute el comando ruby -v Si su versioacuten es adecuadausted puede proceder a la seccioacuten de Gems

Si su versioacuten de ruby no es compatible con rails usted tiene dos opciones

1 Checar si su sistema operativo necesita actualizacioacuten y la versioacuten actualizada incluye un nuevo Ruby En la actualidad los sistemas Linux tienden a tener los maacutes nuevas instalaciones de Ruby en binario En sistemas Solaris algunos usuarios utilizan los paquetes binarios de CSW blastwave para mantenersus sistemas solaris actualizados sin tener que instalar un compilador en la maacutequinaEn Mac OS X depende de su versioacuten del sistema operativo El wiki de RubyGarden tiene informacioacutenacerca de como instalar los binarios

2 Instalar ruby en usrlocal ya sea en binario o compilado

Nota Muchos administradores de sistema Unix (en especial deLinux) prefieren instalar los sistemas de web compilando losarchivos fuente Esto permite el control absoluto de su ambientepero requiere de mayor conocimiento de su sistema asiacute como uncompilador

Si usted decide instalar un sistema ruby desde coacutedigo fuente baje el coacutedigo fuente del sitiooficial de Ruby (en Mac OS X tambieacuten necesita instalar las herramientas XCode quenormalmente vienen incluidos en sus discos del sistema operativo) y utilice la maneraestaacutendar de compilar programas en Unix

$ cd ruby-184-src

$ configure --prefix=usrlocal

$ make$ make install

Despueacutes de instalarlo antildeada el directorio usrlocalrubybin a su variable PATH

Recuerde Si su maacutequina ya incluiacutea ruby el directorio de su nuevacopia de Ruby debe estar antes de los demaacutes directorios en suvariable PATH

Ahora verifique que su instalacioacuten funciona ejecutando ruby -v yverificando la nueva versioacuten

Ruby en Windows

Como mencioneacute anteriormente ruby se encuentra maacutes en casa en un sistema Unix Elproblema principal de Windows es que eacuteste sistema operativo no viene con un compilador -los usuarios de Windows se sienten maacutes comodos con paquetes en binarios y con instalador

Si usted no tiene deseo de aprender a manejar un sistema Unix usted puede utilizar el OneClick Ruby Installer for Windows Este es un instalador que incluye ruby muchas libreriacuteas enbinario y el libro Programming Ruby The Pragmatic Programmers Guide en un archivo de

ayuda Una vez instalado sencillamente ejecute una liacutenea de comando y escriba ruby -vpara verificar su versioacuten

Pero si usted quisiera instalar un subsistema tipo Unix bajo Windows (o si usted estaacuteobligado a usar Windows por su trabajo pero prefiere usar Linux en casa) usted puedeinstalar Cygwin que es una recompilacioacuten de las utileriacuteas GNU bajo windows Durante lainstalacioacuten seleccione Ruby para que se encuentre incluido

Ruby Gems

RubyGems es un manejador de libreriacuteas de Ruby que hace muy sencillo instalar libreriacuteasGems esta a punto de convertirse en parte de ruby Pero si gems no estaacute incluido en suversioacuten de ruby (lo cual puede verificar ejecutando gem -v para ver la versioacuten de gemsinstalada) lo necesita instalar Como usted ya tiene ruby el procedimiento para instalarlo esel mismo para todos los sistemas operativos

cd rubygems

ruby setuprb gem -v

Ahora que tiene ruby gems puede proceder a instalar rails

MySQL

Ahora necesita una base de datos Si usted utiliza Unix es importante instalarla antes deinstalar el paquete mysql de gems porque las libreriacuteas de cliente de mysql son necesarias

Para instalar mysql baje la versioacuten para su plataforma del sitio de internet de MySQLcomUna vez que la instale puede proceder a instalar rails

Rails

Ahora siacute podemos instalar rails Para instalar rails ejecute lo siguiente

$ sudo gem install rails --include-dependencies$ sudo gem install mysql --with-mysql-dir=usrlocalmysql

El paraacutemetro with-mysql-dir soacutelo es necesario si su mysql no instala correctamente (porqueel compilador no encontroacute las libreriacuteas de mysql) Aseguacuterese de que el directorio queutilizaen el paraacutemetro sea el directorio donde instaloacute mysql

Finalmente ejecute el comando rails --version para verificar que su versioacuten de rails fueacuteinstalada correctamente

3 Nuestra primera aplicacioacuten

Creando un Esqueleto

Uno comienza con su aplicacioacuten de Rails creando un esqueleto Crear un esqueleto es muyfacil

$ rails direcciones

create

create appapis

create appcontrollers

create apphelpers

create appmodels

create appviewslayouts

create configenvironments

create components

create db

create doc

create lib

create log

create publicimages

create publicjavascripts

create publicstylesheets

create script

create testfixtures

create testfunctional

create testmocksdevelopment

create testmockstest

create testunit

Facil no Ahora veamos lo que creamos Para esto necesitamos ejecutar un servidor Railspuede ser configurado con apache y FastCGI Pero nuestro esqueleto tambien cuenta conun pequentildeo servidor web Asiacute que lo ejecutamos

$ cd direcciones

$ ruby scriptserver

=gt Rails application started on http00003000

=gt Ctrl-C to shutdown server call with --help for options

[2005-12-06 232744] INFO WEBrick 131[2005-12-06 232744] INFO ruby 182 (2004-12-25) [i386-

mswin32][2005-12-06 232745] INFO WEBrickHTTPServerstart pid=3972

port=3000

Note el puerto que el servidor nos ha dedicado 3000 Este es el puerto que vamos aaccesar utilizando nuestro navegador favorito La direccion es localhost o 127001 Asiacute queen nuestro navegador iremos a http1270013000 Si todo salioacute bien veremos unapantalla de felicitaciones con instrucciones para configurar Apache y pasos siguientes

Ahora que tenemos nuestra aplicacioacuten de rails lista podemos comenzar a ver como estaacutecompuesta nuestra nueva aplicacioacuten

Tu ambiente

Rails 11 tiene un enlace llamado About yourApplications environment que le permite verificarinformacioacuten acerca del ambiente Esta informacioacuten seencuentra en el URL rails_infoproperties

Anatomiacutea de una Aplicacioacuten Rails

Una aplicacioacuten rails se encuentra en el subdirectorio app y se compone de los siguientesdirectorios

apis - las libreriacuteas que su programa requiere fuera de Rails mismocontrollers - Los controladoreshelpers - Los helpersmodels - Los modelos Basicamente las clases que representan los datos que nuestra aplicacioacutenmanipularaacuteviews - Las vistas que son archivos rhtml (como JSP o ASP)

viewslayouts - Los disentildeos Cada controlador tiene su propio disentildeo donde se pondran las cabeceras ypies de paacuteginaconfig - Archivos de configuracioacuten La configuracioacuten de la base de datos se encuentra aquiacutescript - Utileriacuteas para generar coacutedigo y ejecutar el servidorpublic - La raiacutez del directorio virtual Cualquier contenido que usted encuentre aquiacute seraacute publicado en suaplicacioacuten directamente En una nueva aplicacioacuten usted puede encontrar las paacuteginas web para loserrores 404 y 500 las imaacutegenes javascripts estilos etceacuteteratest - Los archivos para las pruebas funcionales y de unidad

Llamando coacutedigo

Seguramente querremos que nuestro directorio tenga una pantalla principalConceptualmente llamaremos a esto el moacutedulo principal Asiacute que lo generamos

$ ruby scriptgenerate controller principal

exists appcontrollers

exists apphelpers

create appviewsprincipal

exists testfunctional

create appcontrollersprincipal_controllerrb

create testfunctionalprincipal_controller_testrb

create apphelpersprincipal_helperrb

Ahora puede usted visitar http1270013000principal para ver

Unknown actionNo action responded to index

El archivo que fue creado se llama controllersprincipal_controllerrb Vamos aponer nuestro coacutedigo ahiacute

class PrincipalController lt ApplicationController

def index

mensaje = Hola a todosltbrgt

[Pedro Pablo Juan]each do |nombre|

mensaje += y a +nombre+ tambienltbrgt

end

render text =gt mensaje

end

end

Cuando visitamos de nuevo vemos nuestro resultado

Hola a todosy a Pedro tambieny a Pablo tambieny a Juan tambien

Finalmente queremos que la raiacutez de esta aplicacioacuten sea tambieacuten nuestro controlador Asiacuteque eliminamos el indexhtml de bienvenida

$ rm publicindexhtml

Si vemos la paacutegina de nuevo ahora diraacute

Routing ErrorRecognition failed for

Esto es porque todaviacutea no le hemos dicho a la aplicacioacuten que nuestro controlador pordefecto es el principal Podemos hacer esto definiendo una ruta Asiacute que modificamos laconfiguracioacuten de rutas en el archivo configroutesrb

mapconnect controller =gt principal

Ahora cuando visitamos la paacutegina vemos el resultado de nuestro controlador principal

Si tiene dudas puede ver la peliacutecula

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 6: Tutorial de Ruby on Rails

necesidades Es recomendable que lea todo lo relevante a la plataforma que desee instalarantes de que haga una decisioacuten acerca de coacutemo instalarlo

Ruby en Unix Linux y Mac OS X

Si usted tiene una maacutequina que proviene de la familia Unix (incluyendo Mac OS X) esprobable que ya tenga Ruby incluido Rails requiere de ruby 182 o 184 (pero 183 nofunciona)

Para verificar su versioacuten de ruby ejecute el comando ruby -v Si su versioacuten es adecuadausted puede proceder a la seccioacuten de Gems

Si su versioacuten de ruby no es compatible con rails usted tiene dos opciones

1 Checar si su sistema operativo necesita actualizacioacuten y la versioacuten actualizada incluye un nuevo Ruby En la actualidad los sistemas Linux tienden a tener los maacutes nuevas instalaciones de Ruby en binario En sistemas Solaris algunos usuarios utilizan los paquetes binarios de CSW blastwave para mantenersus sistemas solaris actualizados sin tener que instalar un compilador en la maacutequinaEn Mac OS X depende de su versioacuten del sistema operativo El wiki de RubyGarden tiene informacioacutenacerca de como instalar los binarios

2 Instalar ruby en usrlocal ya sea en binario o compilado

Nota Muchos administradores de sistema Unix (en especial deLinux) prefieren instalar los sistemas de web compilando losarchivos fuente Esto permite el control absoluto de su ambientepero requiere de mayor conocimiento de su sistema asiacute como uncompilador

Si usted decide instalar un sistema ruby desde coacutedigo fuente baje el coacutedigo fuente del sitiooficial de Ruby (en Mac OS X tambieacuten necesita instalar las herramientas XCode quenormalmente vienen incluidos en sus discos del sistema operativo) y utilice la maneraestaacutendar de compilar programas en Unix

$ cd ruby-184-src

$ configure --prefix=usrlocal

$ make$ make install

Despueacutes de instalarlo antildeada el directorio usrlocalrubybin a su variable PATH

Recuerde Si su maacutequina ya incluiacutea ruby el directorio de su nuevacopia de Ruby debe estar antes de los demaacutes directorios en suvariable PATH

Ahora verifique que su instalacioacuten funciona ejecutando ruby -v yverificando la nueva versioacuten

Ruby en Windows

Como mencioneacute anteriormente ruby se encuentra maacutes en casa en un sistema Unix Elproblema principal de Windows es que eacuteste sistema operativo no viene con un compilador -los usuarios de Windows se sienten maacutes comodos con paquetes en binarios y con instalador

Si usted no tiene deseo de aprender a manejar un sistema Unix usted puede utilizar el OneClick Ruby Installer for Windows Este es un instalador que incluye ruby muchas libreriacuteas enbinario y el libro Programming Ruby The Pragmatic Programmers Guide en un archivo de

ayuda Una vez instalado sencillamente ejecute una liacutenea de comando y escriba ruby -vpara verificar su versioacuten

Pero si usted quisiera instalar un subsistema tipo Unix bajo Windows (o si usted estaacuteobligado a usar Windows por su trabajo pero prefiere usar Linux en casa) usted puedeinstalar Cygwin que es una recompilacioacuten de las utileriacuteas GNU bajo windows Durante lainstalacioacuten seleccione Ruby para que se encuentre incluido

Ruby Gems

RubyGems es un manejador de libreriacuteas de Ruby que hace muy sencillo instalar libreriacuteasGems esta a punto de convertirse en parte de ruby Pero si gems no estaacute incluido en suversioacuten de ruby (lo cual puede verificar ejecutando gem -v para ver la versioacuten de gemsinstalada) lo necesita instalar Como usted ya tiene ruby el procedimiento para instalarlo esel mismo para todos los sistemas operativos

cd rubygems

ruby setuprb gem -v

Ahora que tiene ruby gems puede proceder a instalar rails

MySQL

Ahora necesita una base de datos Si usted utiliza Unix es importante instalarla antes deinstalar el paquete mysql de gems porque las libreriacuteas de cliente de mysql son necesarias

Para instalar mysql baje la versioacuten para su plataforma del sitio de internet de MySQLcomUna vez que la instale puede proceder a instalar rails

Rails

Ahora siacute podemos instalar rails Para instalar rails ejecute lo siguiente

$ sudo gem install rails --include-dependencies$ sudo gem install mysql --with-mysql-dir=usrlocalmysql

El paraacutemetro with-mysql-dir soacutelo es necesario si su mysql no instala correctamente (porqueel compilador no encontroacute las libreriacuteas de mysql) Aseguacuterese de que el directorio queutilizaen el paraacutemetro sea el directorio donde instaloacute mysql

Finalmente ejecute el comando rails --version para verificar que su versioacuten de rails fueacuteinstalada correctamente

3 Nuestra primera aplicacioacuten

Creando un Esqueleto

Uno comienza con su aplicacioacuten de Rails creando un esqueleto Crear un esqueleto es muyfacil

$ rails direcciones

create

create appapis

create appcontrollers

create apphelpers

create appmodels

create appviewslayouts

create configenvironments

create components

create db

create doc

create lib

create log

create publicimages

create publicjavascripts

create publicstylesheets

create script

create testfixtures

create testfunctional

create testmocksdevelopment

create testmockstest

create testunit

Facil no Ahora veamos lo que creamos Para esto necesitamos ejecutar un servidor Railspuede ser configurado con apache y FastCGI Pero nuestro esqueleto tambien cuenta conun pequentildeo servidor web Asiacute que lo ejecutamos

$ cd direcciones

$ ruby scriptserver

=gt Rails application started on http00003000

=gt Ctrl-C to shutdown server call with --help for options

[2005-12-06 232744] INFO WEBrick 131[2005-12-06 232744] INFO ruby 182 (2004-12-25) [i386-

mswin32][2005-12-06 232745] INFO WEBrickHTTPServerstart pid=3972

port=3000

Note el puerto que el servidor nos ha dedicado 3000 Este es el puerto que vamos aaccesar utilizando nuestro navegador favorito La direccion es localhost o 127001 Asiacute queen nuestro navegador iremos a http1270013000 Si todo salioacute bien veremos unapantalla de felicitaciones con instrucciones para configurar Apache y pasos siguientes

Ahora que tenemos nuestra aplicacioacuten de rails lista podemos comenzar a ver como estaacutecompuesta nuestra nueva aplicacioacuten

Tu ambiente

Rails 11 tiene un enlace llamado About yourApplications environment que le permite verificarinformacioacuten acerca del ambiente Esta informacioacuten seencuentra en el URL rails_infoproperties

Anatomiacutea de una Aplicacioacuten Rails

Una aplicacioacuten rails se encuentra en el subdirectorio app y se compone de los siguientesdirectorios

apis - las libreriacuteas que su programa requiere fuera de Rails mismocontrollers - Los controladoreshelpers - Los helpersmodels - Los modelos Basicamente las clases que representan los datos que nuestra aplicacioacutenmanipularaacuteviews - Las vistas que son archivos rhtml (como JSP o ASP)

viewslayouts - Los disentildeos Cada controlador tiene su propio disentildeo donde se pondran las cabeceras ypies de paacuteginaconfig - Archivos de configuracioacuten La configuracioacuten de la base de datos se encuentra aquiacutescript - Utileriacuteas para generar coacutedigo y ejecutar el servidorpublic - La raiacutez del directorio virtual Cualquier contenido que usted encuentre aquiacute seraacute publicado en suaplicacioacuten directamente En una nueva aplicacioacuten usted puede encontrar las paacuteginas web para loserrores 404 y 500 las imaacutegenes javascripts estilos etceacuteteratest - Los archivos para las pruebas funcionales y de unidad

Llamando coacutedigo

Seguramente querremos que nuestro directorio tenga una pantalla principalConceptualmente llamaremos a esto el moacutedulo principal Asiacute que lo generamos

$ ruby scriptgenerate controller principal

exists appcontrollers

exists apphelpers

create appviewsprincipal

exists testfunctional

create appcontrollersprincipal_controllerrb

create testfunctionalprincipal_controller_testrb

create apphelpersprincipal_helperrb

Ahora puede usted visitar http1270013000principal para ver

Unknown actionNo action responded to index

El archivo que fue creado se llama controllersprincipal_controllerrb Vamos aponer nuestro coacutedigo ahiacute

class PrincipalController lt ApplicationController

def index

mensaje = Hola a todosltbrgt

[Pedro Pablo Juan]each do |nombre|

mensaje += y a +nombre+ tambienltbrgt

end

render text =gt mensaje

end

end

Cuando visitamos de nuevo vemos nuestro resultado

Hola a todosy a Pedro tambieny a Pablo tambieny a Juan tambien

Finalmente queremos que la raiacutez de esta aplicacioacuten sea tambieacuten nuestro controlador Asiacuteque eliminamos el indexhtml de bienvenida

$ rm publicindexhtml

Si vemos la paacutegina de nuevo ahora diraacute

Routing ErrorRecognition failed for

Esto es porque todaviacutea no le hemos dicho a la aplicacioacuten que nuestro controlador pordefecto es el principal Podemos hacer esto definiendo una ruta Asiacute que modificamos laconfiguracioacuten de rutas en el archivo configroutesrb

mapconnect controller =gt principal

Ahora cuando visitamos la paacutegina vemos el resultado de nuestro controlador principal

Si tiene dudas puede ver la peliacutecula

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 7: Tutorial de Ruby on Rails

ayuda Una vez instalado sencillamente ejecute una liacutenea de comando y escriba ruby -vpara verificar su versioacuten

Pero si usted quisiera instalar un subsistema tipo Unix bajo Windows (o si usted estaacuteobligado a usar Windows por su trabajo pero prefiere usar Linux en casa) usted puedeinstalar Cygwin que es una recompilacioacuten de las utileriacuteas GNU bajo windows Durante lainstalacioacuten seleccione Ruby para que se encuentre incluido

Ruby Gems

RubyGems es un manejador de libreriacuteas de Ruby que hace muy sencillo instalar libreriacuteasGems esta a punto de convertirse en parte de ruby Pero si gems no estaacute incluido en suversioacuten de ruby (lo cual puede verificar ejecutando gem -v para ver la versioacuten de gemsinstalada) lo necesita instalar Como usted ya tiene ruby el procedimiento para instalarlo esel mismo para todos los sistemas operativos

cd rubygems

ruby setuprb gem -v

Ahora que tiene ruby gems puede proceder a instalar rails

MySQL

Ahora necesita una base de datos Si usted utiliza Unix es importante instalarla antes deinstalar el paquete mysql de gems porque las libreriacuteas de cliente de mysql son necesarias

Para instalar mysql baje la versioacuten para su plataforma del sitio de internet de MySQLcomUna vez que la instale puede proceder a instalar rails

Rails

Ahora siacute podemos instalar rails Para instalar rails ejecute lo siguiente

$ sudo gem install rails --include-dependencies$ sudo gem install mysql --with-mysql-dir=usrlocalmysql

El paraacutemetro with-mysql-dir soacutelo es necesario si su mysql no instala correctamente (porqueel compilador no encontroacute las libreriacuteas de mysql) Aseguacuterese de que el directorio queutilizaen el paraacutemetro sea el directorio donde instaloacute mysql

Finalmente ejecute el comando rails --version para verificar que su versioacuten de rails fueacuteinstalada correctamente

3 Nuestra primera aplicacioacuten

Creando un Esqueleto

Uno comienza con su aplicacioacuten de Rails creando un esqueleto Crear un esqueleto es muyfacil

$ rails direcciones

create

create appapis

create appcontrollers

create apphelpers

create appmodels

create appviewslayouts

create configenvironments

create components

create db

create doc

create lib

create log

create publicimages

create publicjavascripts

create publicstylesheets

create script

create testfixtures

create testfunctional

create testmocksdevelopment

create testmockstest

create testunit

Facil no Ahora veamos lo que creamos Para esto necesitamos ejecutar un servidor Railspuede ser configurado con apache y FastCGI Pero nuestro esqueleto tambien cuenta conun pequentildeo servidor web Asiacute que lo ejecutamos

$ cd direcciones

$ ruby scriptserver

=gt Rails application started on http00003000

=gt Ctrl-C to shutdown server call with --help for options

[2005-12-06 232744] INFO WEBrick 131[2005-12-06 232744] INFO ruby 182 (2004-12-25) [i386-

mswin32][2005-12-06 232745] INFO WEBrickHTTPServerstart pid=3972

port=3000

Note el puerto que el servidor nos ha dedicado 3000 Este es el puerto que vamos aaccesar utilizando nuestro navegador favorito La direccion es localhost o 127001 Asiacute queen nuestro navegador iremos a http1270013000 Si todo salioacute bien veremos unapantalla de felicitaciones con instrucciones para configurar Apache y pasos siguientes

Ahora que tenemos nuestra aplicacioacuten de rails lista podemos comenzar a ver como estaacutecompuesta nuestra nueva aplicacioacuten

Tu ambiente

Rails 11 tiene un enlace llamado About yourApplications environment que le permite verificarinformacioacuten acerca del ambiente Esta informacioacuten seencuentra en el URL rails_infoproperties

Anatomiacutea de una Aplicacioacuten Rails

Una aplicacioacuten rails se encuentra en el subdirectorio app y se compone de los siguientesdirectorios

apis - las libreriacuteas que su programa requiere fuera de Rails mismocontrollers - Los controladoreshelpers - Los helpersmodels - Los modelos Basicamente las clases que representan los datos que nuestra aplicacioacutenmanipularaacuteviews - Las vistas que son archivos rhtml (como JSP o ASP)

viewslayouts - Los disentildeos Cada controlador tiene su propio disentildeo donde se pondran las cabeceras ypies de paacuteginaconfig - Archivos de configuracioacuten La configuracioacuten de la base de datos se encuentra aquiacutescript - Utileriacuteas para generar coacutedigo y ejecutar el servidorpublic - La raiacutez del directorio virtual Cualquier contenido que usted encuentre aquiacute seraacute publicado en suaplicacioacuten directamente En una nueva aplicacioacuten usted puede encontrar las paacuteginas web para loserrores 404 y 500 las imaacutegenes javascripts estilos etceacuteteratest - Los archivos para las pruebas funcionales y de unidad

Llamando coacutedigo

Seguramente querremos que nuestro directorio tenga una pantalla principalConceptualmente llamaremos a esto el moacutedulo principal Asiacute que lo generamos

$ ruby scriptgenerate controller principal

exists appcontrollers

exists apphelpers

create appviewsprincipal

exists testfunctional

create appcontrollersprincipal_controllerrb

create testfunctionalprincipal_controller_testrb

create apphelpersprincipal_helperrb

Ahora puede usted visitar http1270013000principal para ver

Unknown actionNo action responded to index

El archivo que fue creado se llama controllersprincipal_controllerrb Vamos aponer nuestro coacutedigo ahiacute

class PrincipalController lt ApplicationController

def index

mensaje = Hola a todosltbrgt

[Pedro Pablo Juan]each do |nombre|

mensaje += y a +nombre+ tambienltbrgt

end

render text =gt mensaje

end

end

Cuando visitamos de nuevo vemos nuestro resultado

Hola a todosy a Pedro tambieny a Pablo tambieny a Juan tambien

Finalmente queremos que la raiacutez de esta aplicacioacuten sea tambieacuten nuestro controlador Asiacuteque eliminamos el indexhtml de bienvenida

$ rm publicindexhtml

Si vemos la paacutegina de nuevo ahora diraacute

Routing ErrorRecognition failed for

Esto es porque todaviacutea no le hemos dicho a la aplicacioacuten que nuestro controlador pordefecto es el principal Podemos hacer esto definiendo una ruta Asiacute que modificamos laconfiguracioacuten de rutas en el archivo configroutesrb

mapconnect controller =gt principal

Ahora cuando visitamos la paacutegina vemos el resultado de nuestro controlador principal

Si tiene dudas puede ver la peliacutecula

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 8: Tutorial de Ruby on Rails

3 Nuestra primera aplicacioacuten

Creando un Esqueleto

Uno comienza con su aplicacioacuten de Rails creando un esqueleto Crear un esqueleto es muyfacil

$ rails direcciones

create

create appapis

create appcontrollers

create apphelpers

create appmodels

create appviewslayouts

create configenvironments

create components

create db

create doc

create lib

create log

create publicimages

create publicjavascripts

create publicstylesheets

create script

create testfixtures

create testfunctional

create testmocksdevelopment

create testmockstest

create testunit

Facil no Ahora veamos lo que creamos Para esto necesitamos ejecutar un servidor Railspuede ser configurado con apache y FastCGI Pero nuestro esqueleto tambien cuenta conun pequentildeo servidor web Asiacute que lo ejecutamos

$ cd direcciones

$ ruby scriptserver

=gt Rails application started on http00003000

=gt Ctrl-C to shutdown server call with --help for options

[2005-12-06 232744] INFO WEBrick 131[2005-12-06 232744] INFO ruby 182 (2004-12-25) [i386-

mswin32][2005-12-06 232745] INFO WEBrickHTTPServerstart pid=3972

port=3000

Note el puerto que el servidor nos ha dedicado 3000 Este es el puerto que vamos aaccesar utilizando nuestro navegador favorito La direccion es localhost o 127001 Asiacute queen nuestro navegador iremos a http1270013000 Si todo salioacute bien veremos unapantalla de felicitaciones con instrucciones para configurar Apache y pasos siguientes

Ahora que tenemos nuestra aplicacioacuten de rails lista podemos comenzar a ver como estaacutecompuesta nuestra nueva aplicacioacuten

Tu ambiente

Rails 11 tiene un enlace llamado About yourApplications environment que le permite verificarinformacioacuten acerca del ambiente Esta informacioacuten seencuentra en el URL rails_infoproperties

Anatomiacutea de una Aplicacioacuten Rails

Una aplicacioacuten rails se encuentra en el subdirectorio app y se compone de los siguientesdirectorios

apis - las libreriacuteas que su programa requiere fuera de Rails mismocontrollers - Los controladoreshelpers - Los helpersmodels - Los modelos Basicamente las clases que representan los datos que nuestra aplicacioacutenmanipularaacuteviews - Las vistas que son archivos rhtml (como JSP o ASP)

viewslayouts - Los disentildeos Cada controlador tiene su propio disentildeo donde se pondran las cabeceras ypies de paacuteginaconfig - Archivos de configuracioacuten La configuracioacuten de la base de datos se encuentra aquiacutescript - Utileriacuteas para generar coacutedigo y ejecutar el servidorpublic - La raiacutez del directorio virtual Cualquier contenido que usted encuentre aquiacute seraacute publicado en suaplicacioacuten directamente En una nueva aplicacioacuten usted puede encontrar las paacuteginas web para loserrores 404 y 500 las imaacutegenes javascripts estilos etceacuteteratest - Los archivos para las pruebas funcionales y de unidad

Llamando coacutedigo

Seguramente querremos que nuestro directorio tenga una pantalla principalConceptualmente llamaremos a esto el moacutedulo principal Asiacute que lo generamos

$ ruby scriptgenerate controller principal

exists appcontrollers

exists apphelpers

create appviewsprincipal

exists testfunctional

create appcontrollersprincipal_controllerrb

create testfunctionalprincipal_controller_testrb

create apphelpersprincipal_helperrb

Ahora puede usted visitar http1270013000principal para ver

Unknown actionNo action responded to index

El archivo que fue creado se llama controllersprincipal_controllerrb Vamos aponer nuestro coacutedigo ahiacute

class PrincipalController lt ApplicationController

def index

mensaje = Hola a todosltbrgt

[Pedro Pablo Juan]each do |nombre|

mensaje += y a +nombre+ tambienltbrgt

end

render text =gt mensaje

end

end

Cuando visitamos de nuevo vemos nuestro resultado

Hola a todosy a Pedro tambieny a Pablo tambieny a Juan tambien

Finalmente queremos que la raiacutez de esta aplicacioacuten sea tambieacuten nuestro controlador Asiacuteque eliminamos el indexhtml de bienvenida

$ rm publicindexhtml

Si vemos la paacutegina de nuevo ahora diraacute

Routing ErrorRecognition failed for

Esto es porque todaviacutea no le hemos dicho a la aplicacioacuten que nuestro controlador pordefecto es el principal Podemos hacer esto definiendo una ruta Asiacute que modificamos laconfiguracioacuten de rutas en el archivo configroutesrb

mapconnect controller =gt principal

Ahora cuando visitamos la paacutegina vemos el resultado de nuestro controlador principal

Si tiene dudas puede ver la peliacutecula

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 9: Tutorial de Ruby on Rails

Ahora que tenemos nuestra aplicacioacuten de rails lista podemos comenzar a ver como estaacutecompuesta nuestra nueva aplicacioacuten

Tu ambiente

Rails 11 tiene un enlace llamado About yourApplications environment que le permite verificarinformacioacuten acerca del ambiente Esta informacioacuten seencuentra en el URL rails_infoproperties

Anatomiacutea de una Aplicacioacuten Rails

Una aplicacioacuten rails se encuentra en el subdirectorio app y se compone de los siguientesdirectorios

apis - las libreriacuteas que su programa requiere fuera de Rails mismocontrollers - Los controladoreshelpers - Los helpersmodels - Los modelos Basicamente las clases que representan los datos que nuestra aplicacioacutenmanipularaacuteviews - Las vistas que son archivos rhtml (como JSP o ASP)

viewslayouts - Los disentildeos Cada controlador tiene su propio disentildeo donde se pondran las cabeceras ypies de paacuteginaconfig - Archivos de configuracioacuten La configuracioacuten de la base de datos se encuentra aquiacutescript - Utileriacuteas para generar coacutedigo y ejecutar el servidorpublic - La raiacutez del directorio virtual Cualquier contenido que usted encuentre aquiacute seraacute publicado en suaplicacioacuten directamente En una nueva aplicacioacuten usted puede encontrar las paacuteginas web para loserrores 404 y 500 las imaacutegenes javascripts estilos etceacuteteratest - Los archivos para las pruebas funcionales y de unidad

Llamando coacutedigo

Seguramente querremos que nuestro directorio tenga una pantalla principalConceptualmente llamaremos a esto el moacutedulo principal Asiacute que lo generamos

$ ruby scriptgenerate controller principal

exists appcontrollers

exists apphelpers

create appviewsprincipal

exists testfunctional

create appcontrollersprincipal_controllerrb

create testfunctionalprincipal_controller_testrb

create apphelpersprincipal_helperrb

Ahora puede usted visitar http1270013000principal para ver

Unknown actionNo action responded to index

El archivo que fue creado se llama controllersprincipal_controllerrb Vamos aponer nuestro coacutedigo ahiacute

class PrincipalController lt ApplicationController

def index

mensaje = Hola a todosltbrgt

[Pedro Pablo Juan]each do |nombre|

mensaje += y a +nombre+ tambienltbrgt

end

render text =gt mensaje

end

end

Cuando visitamos de nuevo vemos nuestro resultado

Hola a todosy a Pedro tambieny a Pablo tambieny a Juan tambien

Finalmente queremos que la raiacutez de esta aplicacioacuten sea tambieacuten nuestro controlador Asiacuteque eliminamos el indexhtml de bienvenida

$ rm publicindexhtml

Si vemos la paacutegina de nuevo ahora diraacute

Routing ErrorRecognition failed for

Esto es porque todaviacutea no le hemos dicho a la aplicacioacuten que nuestro controlador pordefecto es el principal Podemos hacer esto definiendo una ruta Asiacute que modificamos laconfiguracioacuten de rutas en el archivo configroutesrb

mapconnect controller =gt principal

Ahora cuando visitamos la paacutegina vemos el resultado de nuestro controlador principal

Si tiene dudas puede ver la peliacutecula

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 10: Tutorial de Ruby on Rails

viewslayouts - Los disentildeos Cada controlador tiene su propio disentildeo donde se pondran las cabeceras ypies de paacuteginaconfig - Archivos de configuracioacuten La configuracioacuten de la base de datos se encuentra aquiacutescript - Utileriacuteas para generar coacutedigo y ejecutar el servidorpublic - La raiacutez del directorio virtual Cualquier contenido que usted encuentre aquiacute seraacute publicado en suaplicacioacuten directamente En una nueva aplicacioacuten usted puede encontrar las paacuteginas web para loserrores 404 y 500 las imaacutegenes javascripts estilos etceacuteteratest - Los archivos para las pruebas funcionales y de unidad

Llamando coacutedigo

Seguramente querremos que nuestro directorio tenga una pantalla principalConceptualmente llamaremos a esto el moacutedulo principal Asiacute que lo generamos

$ ruby scriptgenerate controller principal

exists appcontrollers

exists apphelpers

create appviewsprincipal

exists testfunctional

create appcontrollersprincipal_controllerrb

create testfunctionalprincipal_controller_testrb

create apphelpersprincipal_helperrb

Ahora puede usted visitar http1270013000principal para ver

Unknown actionNo action responded to index

El archivo que fue creado se llama controllersprincipal_controllerrb Vamos aponer nuestro coacutedigo ahiacute

class PrincipalController lt ApplicationController

def index

mensaje = Hola a todosltbrgt

[Pedro Pablo Juan]each do |nombre|

mensaje += y a +nombre+ tambienltbrgt

end

render text =gt mensaje

end

end

Cuando visitamos de nuevo vemos nuestro resultado

Hola a todosy a Pedro tambieny a Pablo tambieny a Juan tambien

Finalmente queremos que la raiacutez de esta aplicacioacuten sea tambieacuten nuestro controlador Asiacuteque eliminamos el indexhtml de bienvenida

$ rm publicindexhtml

Si vemos la paacutegina de nuevo ahora diraacute

Routing ErrorRecognition failed for

Esto es porque todaviacutea no le hemos dicho a la aplicacioacuten que nuestro controlador pordefecto es el principal Podemos hacer esto definiendo una ruta Asiacute que modificamos laconfiguracioacuten de rutas en el archivo configroutesrb

mapconnect controller =gt principal

Ahora cuando visitamos la paacutegina vemos el resultado de nuestro controlador principal

Si tiene dudas puede ver la peliacutecula

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 11: Tutorial de Ruby on Rails

Esto es porque todaviacutea no le hemos dicho a la aplicacioacuten que nuestro controlador pordefecto es el principal Podemos hacer esto definiendo una ruta Asiacute que modificamos laconfiguracioacuten de rutas en el archivo configroutesrb

mapconnect controller =gt principal

Ahora cuando visitamos la paacutegina vemos el resultado de nuestro controlador principal

Si tiene dudas puede ver la peliacutecula

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 12: Tutorial de Ruby on Rails

4 Teoriacutea El Paradigma MVC

MVC son las siglas de Modelo Vista y Controlador Es el patroacuten de disentildeo de software muacuteycomuacuten en programas interactivos orientados a objetos

Bajo el patroacuten de disentildeo de MVC dentro de un programa cada dominio loacutegico de edicioacuten(por ejemplo datos personales cuentas bancarias artiacuteculos noticiosos etceacutetera) necesitatres partes

1 El modelo que es una representacioacuten de objetos del dominio loacutegico En el ejemplo de datos personalesobjetos como Persona Direccioacuten y Teleacutefono

2 La vista que es una o varias piezas de coacutedigo que formatean y muestran todo o parte del modelo en eldispositivo interactivo (tiacutepicamente la pantalla) La vista tiacutepicamente es notificada de cambios en elmodelo

3 El controlador que interpreta la informacioacuten que el usuario provee para hacer cambios en el modelo

La idea es que al aplicar esta separacioacuten se hace posible crear maacutes de una vista para elmismo modelo (digamos una vista abreviada y una vista detallada) y reutilizar el modelo (yel coacutedigo que guarda el modelo de manera permanente) para escribir utileriacuteas relacionadaso incorporar datos del dominio original en programas maacutes grandes

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 13: Tutorial de Ruby on Rails

5 Teoriacutea Pruebas de Unidad

Introduccioacuten

En cualquir sistema complejo es criacutetico probarlo praa saber que funcionaraacute una vez que selance en vivo Muchos grupos de trabajo se limitan a dedicar una o dos personas a probar elsistema Eacuteste meacutetodo tiene algunos problemas

1 El programador estaacute separado de la prueba Esto impide que el programador proporcione informacioacutenacerca de condiciones extremas de prueba y el aislamiento tambieacuten provoca que el programador sigacometiendo los mismos errores por no tener informacioacuten acerca de como se prueba su sistema

2 Una prueba que se limita a utilizar el sistema como un usuario no cubre problemas de disentildeo de objetosMientras el programa crece el coacutedigo espagueti se hace maacutes y maacutes complejo El problema se hace peorexponencialmente mientras el sistema se mantenga en esta situacioacuten hasta que arreglarlo se vuelve maacutescaro que comenzar de nuevo

3 Como humanos nos es faacutecil olvidar maneras alternativas de utilizar las mismas funciones Por ejemplo iquestutilizas ArchivoGuardar el boton para guardar o Control-S iquestSi es ArchivoGuardar conel teclado o con el mouse iquestCogravemo sabes que los dos funcionan Todas estas condiciones parecenmultiplicarse diario

Lo que las pruebas de unidad buscan es evitar dichos problemas para que la calidad delsisterma sea mayor Es un hecho comprobado que los sistemas que estaacuten disentildeadosutilizando metodologiacuteas que ponen la prueba como parte integral del disentildeo terminan siendomaacutes confiables

iquestQueacute es una Prueba de Unidad

Una prueba de unidad pretende probar cada funciograven en un archivo de programa simple (unaclase en terminologigravea de objetos) Las libreriacuteas de pruebas de unidad formalizan este trabajoal proporcionar clases para pruebas

La prueba de unidad ayuda a que el mogravedulo se haga independiente Esto quiere decir que unmogravedulo que tiene una prueba de unidad se puede probar independientemente del resto delsistema Una vez que un gran porcentaje de su programa cuente con pruebas de unidad

Note que las pruebas de unidad no sustituyen a las pruebasfuncionales del departamento de control de calidad pero a lalarga reducen la cantidad de errores de regresioacuten en futurasversiones del producto

Una buena prueba de unidad

No requiere de mucho cogravedigo para prepararla- Una prueba de unidad cuya preparaciograven toma 3 minutos(conectagravendose a la base de datos levantando un servidor de web etcegravetera) se debe considerardemasiado pesada para ejecutarse cada vez que se hagan cambiosPrueba soacutelo un meacutetodo Aunque no siempre es necesario hacer una prueba por meacutetodo siacute esimportante asegurar que cubrimos toda la clase Muchas veces se requiere maacutes de un meacutetodo de pruebapor cada meacutetodo en la clase para poder probar diferentes datos y casos extremos (por ejemplo iquestqueacutepasa cuendo el usuario no existe)Verifica los resultados con aserciones De preferencia se debe de checar soacutelo un resultado Se puedenchecar varias partes del mismo resultado pero diferentes condiciones deben probarse en un meacutetodoseparado

>

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 14: Tutorial de Ruby on Rails

Deja los datos de la misma manera en que los encontroacute Cuando la prueba comienza los datos sepreparan si es necesario pero cuando la prueba termina es importante que el sistema borre los datosdespueacutes de la verificacioacuten Es por esto que muchas libreriacuteas de pruebas unitarias tienen meacutetodosllamados setup() y teardown() o similares

Pruebas de Unidad y Disentildeo de Software

Las pruebas de unidad influenciacutean el disentildeo (para bien) Estoquiere decir que el aplicar pruebas de unidad a un sistemapreviamente escrito seraacute difiacutecil Cuando usted se decida a antildeadirpruebas de unidad a un sistema existente aseguacuterese de escojersus batallas y hacer pruebas de regresioacuten del sistema Si susistema es mediano o grande es conveniente planear sus pruebasy aplicar los cambios necesarios a traves de varias versionesfuturas No lo intente todo al mismo tiempo

Cobertura

Otro concepto relacionado a las pruebas de unidad es el de cobertura iquestCoacutemo sabemoscuantas liacuteneas del programa estaacuten siendo probadas (y maacutes importante las que no seprobaron) Una vez que usted tiene pruebas de unidad probablemente le interesaraacute tenerun reporte de las liacuteneas que no se han probado Una utileriacutea gratuita para proporcionar estosreportes en ruby se llama apropriadamente rubycoverage Rubycoverage no viene con rails- usted lo debe instalar utilizando gems

Desarrollo Basado en Pruebas (o Metodologiacutea PruebaPrimero)

Mencionamos anteriormente que las pruebas de unidad influenciacutean positivamente el disentildeode su programa Es por esto que muchas metodologiacuteas aacutegiles son partidarias de lo que sellama probar primero

La idea del desarrollo basado en pruebas consiste en utilizar las pruebas de unidad comouna pre-verificacioacuten y guiacutea para comenzar a escribir el coacutedigo Al escribir la prueba primero(o al menos al mismo tiempo que el moacutedulo original) a la larga es maacutes sencillo mantener elprograma y el disentildeo nunca se perjudica al punto que crea dificultades en el control decalidad

La importancia de Pruebas de Unidad en Rails

En ruby on rails y en todos los lenguajes interpretados en uso hoydiacutea la idea de las pruebas de unidad es central e importantiacutesimaComo casi todos los errores en un programa interpretado soacuteloocurren cuando el programa corre (porque no hay etapa decompilacioacuten) en esta clase de lenguajes es esencial escribir laspruebas de unidad al mismo tiempo que el coacutedigo y asegurar unacobertura adecuada

Las pruebas de unidad y el desarrollo basado en pruebas sonimportantes en todos los lenguajes pero son auacuten maacutes importantesen Ruby y Rails No lo olvide

Por este motivo durante el curso veremos coacutemo podemos escribirnuestras pruebas primero (o al menos al mismo tiempo) que el

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 15: Tutorial de Ruby on Rails

resto del sistema

Basado en el requerimiento primero escribimos una prueba inicial que nos ayudariacutea adeterminar que el requerimiento funciona correctamente en su camino feliz o sea su caminomaacutes sencillo Obviamente la prueba debe fallar porque todaviacutea no hay coacutedigo de verdad

Ahora que la prueba falla podemos comenzar a escribir la implementacioacuten para que laprueba funcione de la manera maacutes sencilla como sea posible

Una vez que tengas tu implementacioacuten inicial podemos hechar un vistazo a los casosexcepcionales Por ejemplo si escribimos un requerimiento que dice que los usuariospueden subscribirse a nuestro sistema ellos mismos y que el sistema les enviaraacute un correoelectroacutenico cuando se suscriban iquestqueacute pasa si el usuario es menor de edad iquestQueacute pasa siel usuario escribe un correo electroacutenico no vaacutelido La idea es crear suficientes pruebas paralos casos diferentes tiacutepicos

Pruebas de Unidad y Rails

Ruby on Rails utiliza la libreriacutea TestUnit como estaacutendar para crear pruebas de unidadCuando usted utiliza los generadores de Rails para crear cualquier moacutedulo ya sea modeloso controladores rails automaacuteticamente crea una prueba de unidad para dicho controlador omodelo en el directorio test incluyendo una que otra prueba baacutesica El disentildeo MVC deRails hace maacutes faacutecil escribir pruebas de unidad Cuando usted extienda el programa soacutelotiene que mantener las pruebas

Ademaacutes el comando rake en una aplicacioacuten de rails ejecuta las pruebas De esta manerausted puede antildeadir las pruebas de unidad y ejecutarlas con un soacutelo comando

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 16: Tutorial de Ruby on Rails

6 Configurando la Base de Datos

Creando una base de Datos en MySQL

Ahora vamos a preparar sus bases de datos Rails utiliza configuraciones por separado paradesarrollo (development) prueba (test) y produccioacuten La idea es que usted desarrolla yprueba en una base de datos y ejecuta las pruebas de unidad apuntando a la base de datosde prueba En general rails no toca el esquema de la base de datos de produccioacuten

La recomendacioacuten es que utilice usted los sufijos _dev para desarrollo _test para pruebay _prod para produccioacuten y que su nombre baacutesico de la base de datos sea el mismo

Notas Acerca de Rails y bases de datos

Por defecto Rails utiliza bases de datos sqlite para desarrolloEsto no tiene nada de malo pero sqlite estaacute disentildeado paraaplicaciones pequentildeas y muy raacutepidas y para implementacioneslocales (sqlite3 es el motor de almacenamiento local para elsubsistema Core Data de Mac OS X por ejemplo) Paraimplementacioacuten de un sistema web donde varios servidores deweb estaacuten conectados a la misma base de datos es preferibleutilizar una base de datos como MySQL o Postgres para queevitar un problema de escalabilidad

Preparando la base de datos de Desarrollo

Para preparar su base de datos de desarrollo en MySQL ejecute los siguientes comandos

$ mysql -h miservidormydominiocom -u root -ppassword mysqlgt create database direcciones_devQuery OK 1 row affected (053 sec)mysqlgt grant all privileges on direcciones_dev to direcciones_dev -gt identified by direccionesQuery OK 0 rows affected (080 sec)mysqlgt Control-DBye

Configurando su Aplicacioacuten

Para configurar su base de datos usted necesita editar el archivo configdatabaseyml para apuntar a su servidor

development adapter mysql database direcciones_dev host miservidormydominiocom username direcciones_dev password direcciones test adapter mysql

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 17: Tutorial de Ruby on Rails

database direcciones_test host miservidormydominiocom username direcciones_test password direcciones production development

Ahora su sistema se puede conectar a la base de datos en la base de datos de desarrolloHaga lo mismo con la base de datos de prueba (crear la base de datos su usuario y losprivilegios en MySQL)

Una vez que su programa esteacute listo su administrador de sistema puede configurar la basede datos del sistema de produccioacuten dentro de este mismo archivo Un sistema se puedeponer en modo de produccioacuten cambiando el valor RAILS_ENV en el archivoconfigenvironmentrb

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 18: Tutorial de Ruby on Rails

7 Creando un Moacutedulo con Modelo Controlador y Vista

Planeando nuestro modelo

Hemos mencionado que lo que queremos hacer en este curso es escribir una libreta dedirecciones Asiacute que comenzaremos a planear nuestro modelo

Diferentes Maneras de crear un Modelo

Hay tres maneras de crear un modelo en un sistema

Pantallas No es muy recomendable pero puede uno basarseen un boceto de las pantallasModelo de Objetos Si usted estaacute acostumbrado a utilizarJava yo a hacer programas que no utilicen bases de datospuede ser que usted utilice un modelo de classes y objetosModelo de base de datos Si usted crea muchasaplicaciones de bases de datos (o es administrador de bases dedatos) usted probablemente crea su modelo de base de datosprimero

El modelo de rails es una combinacioacuten de modelo de base de datosy modelo de objetos En el paradigma de disentildeo tiacutepico ustedmodela las tablas y relaciones de bases de datos y despueacutes crea elcoacutedigo del modelo Eacutesta es la manera recomendable de disentildear elprograma

Creando la tabla en la base de datos

La mejor manera de crear la tabla es utilizando una migracioacuten Una migracioacuten es unconcepto de ActiveRecord que le permite mantener las modificaciones al esquema de subase de datos sincronizadas con la version actual de su coacutedigo Para crear una migracioacutenusted debe hacer lo siguiente

$ cd direcciones$ ruby scriptgenerate migration crea_tabla_personas create dbmigrate create dbmigrate20081102001338_crea_tabla_personasrb

Rails ahora ha creado una clase llamada CreaTablaPersonas (en el archivodbmigrate20081102001338_crea_tabla_personasrb que contiene los meacutetodos selfup yselfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup end

def selfdown endend

>

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 19: Tutorial de Ruby on Rails

Una migracioacuten define los meacutetodos selfup y selfdown para hacer y deshacerrespectivamente sus cambios al esquema Para crear nuestra tabla definimos la tabla conun comando de ruby en selfup Tambieacuten escribiremos el coacutedigo para deshacer nuestroscambios (en este caso eliminar la tabla) en selfdown

class CreaTablaPersonas lt ActiveRecordMigration def selfup create_table personas do |tabla| tablastring nombre limit =gt 80 null =gt false tablastring apellido_paterno limit =gt 80 tablastring apellido_materno limit =gt 80 El nombre que debemos desplegar en pantalla tablastring desplegar limit =gt 80 tablastring sexo limit =gt 10 default =gt Hombre null =gt false tablatext notas end end

def selfdown drop_table personas endend

El resultado de ejecutar la migracioacuten seraacute el siguiente SQL (en mysql)

CREATE TABLE personas ( id int NOT NULL auto_increment nombre varchar(80) default NOT NULL apellido_paterno varchar(80) default NULL apellido_materno varchar(80) default NULL desplegar varchar(80) default NULL sexo varchar(10) default Hombre notas TEXT NULL PRIMARY KEY (id))

Note que el campo identificador (id) se crea automaacuteticamente

Cuando su coacutedigo esteacute listo simplemente ejecute el comando

$ rake dbmigrate

Y el sistema se conectaraacute a la base de datos y ejecutaraacute la migracioacuten

Rails mantiene una tabla en la base de datos llamada schema_info que contiene la versioacutenactual de la base de datos Si usted ejecuta el comando rake migrate VERSION=x la base dedatos cambiaraacute a la versioacuten X ya sea ejecutando los meacutetodos up de las migraciones queno se han hecho o ejecutando los meacutetodos down de las versiones que hay que revertir

Migraciones Irreversibles

De vez en cuando usted necesitaraacute hacer unamigracioacuten irreversible (por ejemplo si necesitaeliminar una columna de la base de datos) Cuandoesto ocurra iexclno deje selfdown vaciacuteo Utiliceraise IrreversibleMigration para que el sistema sepaque los cambios en selfup son irreversibles

Creando un Andamio

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 20: Tutorial de Ruby on Rails

Ahora que tenemos nuestro modelo en la base de datos podemos decirle a rails que creenuestro modelo controlador y vista con un soacutelo comando ejecutando el programa generatecon el nombre de nuestra tabla en MySQL

$ ruby scriptgenerate scaffold persona

exists appmodels

exists testunit

exists testfixtures

create appmodelspersonarb

create testunitpersona_testrb

create testfixturespersonasyml

Para ver como se creoacute el modelo veamos el coacutedigo de personarb

class Personas lt ActiveRecordBase

end

Es algo que puede escribir usted mismo pero usar los generadores le ahorra tiempo y evitaerrores

iquestY las propiedades

Notaraacute que su clase Personas no tiene propiedadesequivalentes a los campos de la base de datos Estoes porque Ruby automaacuteticamete crea propiedadespara los campos de la tabla de Personas en la basede datos Recuerde Ruby utiliza el principio No teRepitas

Esto es muy uacutetil especialmente porque cuandoestamos comenzando en nuestro proyecto muchasveces tenemos que cambiar los nombres de loscampos hasta que los prototipos y el coacutedigo seestabilice

El generador ha creado lo que llamamos un andamiaje (scaffolding)

iquestAndamio iexclSi no soy albantildeil

En construccioacuten un andamio (scaffold) es unaconstruccioacuten muy sencilla que hace posible laconstruccioacuten del edificio real De la misma maneraun el generador crea una construccioacuten sencilla enRails que nos permite antildeadir registros a la base dedatos de inmediato y nos sirve de andamiajehaciendo posible construir el programa real

Ahora podemos comenzar nuestro servidor y navegar a http1270013000personas paraver nuestro andamio y crear algunos registros de prueba

Como veraacute su andamio contiene un listado vista actualizacioacuten y borrado de registros Estoes lo que le llaman en ingleacutes CRUD por las siglas de createreplaceupdatedelete Sulistado tambieacuten le muestra paacuteginas Trate de antildeadir maacutes de diez registros para verlofuncionar

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 21: Tutorial de Ruby on Rails

SingularPlural Note que el estaacutendar de Rails es utilizarplural para los nombres de las tablas en la base de datos (createtable personas) y singular para ejecutar los generadores Elgenerador pluralizaraacute el nombre cuando lo considere adecuado

Rails pluralizoacute automaacuteticamente el nombre persona que le dimos al generador Laestructura pluralsingular queda como sigue

Tabla (en Base de Datos) PERSONAS PluralModelo (en appmodels) personarb SingularVista (en appviews) personasrhtml PluralControlador (en appcontrollers) pesonas_controllerrb PluralPrueba (en testsfunctional) personas_controller_testrb Plural

La idea de la regla es que la uacutenica mencioacuten de singular es cuando creamos el modelo

Si esto no es adecuado a su proyecto usted puede cambiar algunas de estas reglascambiando el archivo configenvironmentrb Algunos de los cambios que le interestaraacutenson

ActiveRecordBasepluralize_table_names (truefalse) le permite decirle a rails que pluralize ono los nombres de las tablas Si su administrador de base de datos no quiere que las tablas esteacuten enplural escriba ActiveRecordBasepluralize_table_names = falseActiveRecordBaseprimary_key_prefix_type (table_nametable_name_with_underscore) lepermite definir la manera en que ActiveRecord calcularaacute el campo identificador por defecto En nuestroejemplo con el valor table_name el campo identificador seriacutea personaid pero con la opcioacutentable_name_with_underscore el campo identificador seriacutea persona_id

El Inflector

ActiveRecord utiliza una clase llamada Inflector para especificar las reglas de pluralizacioacutenUsted puede modificar y antildeadir nuevas reglas de pluralizacioacuten para su aplicacioacuten tambieacutencon configenvironmentrb Simplemente agregue otras reglas utilizando expresionesregulares para definir inflecciones del plural singular irregular o imposible de contar (notiene plural) como sigue

Inflectorinflections do |inflect| inflectplural ^(ox)$i 1en inflectsingular ^(ox)eni 1 inflectirregular person people inflectuncountable w( fish sheep )end

Pero mi Administrador de Base de Datos es muy Estricto

Si su administrador de DB es muy estricto (o la base de datos pertenece a otro programa yno se puede cambiar) usted puede cambiar el nombre de la base de datos en el modelopersonarb cambiando el meacutetodo table_name Por ejemplo trabajamos en un banco enormey tienen estaacutendares de esos que obligan a utilizar nombres ilegibles (pobrecitos) de soacuteloocho caracteres para que sean compatibles con su computadora mainframe de 1970(ouch) y el nombre de la tabla de persona debe ser DC_PERSN

class Personas lt ActiveRecordBase

def selftable_name() DC_PERSN end

end

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 22: Tutorial de Ruby on Rails

Listo

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 23: Tutorial de Ruby on Rails

8 Control de Versiones con Subversion

Subversion es el sistema de control de versiones que utilizaremos a traveacutes de este curso Nodepende ni tiene nada que ver con Ruby o Rails de hecho usted puede utilizar subversioncon cualquier lenguaje de programacioacuten (incluso con cualquier coleccioacuten de archivos paralos cuales usted desee mantener un historial de versiones)

Nota Esto es soacutelo una introduccioacuten baacutesica a subversion paraque pueda comprender los comandos de subversion queejecutareacute de vez en cuando en el curso de rails El tema decontrol de versiones en siacute mismo es un tema enorme Para unamucha mejor explicacioacuten en espantildeol de coacutemo funcionasubversion el libro en liacutenea Control de Versiones conSubversion es mucho maacutes adecuado (y tambieacuten es gratuito)

Programacioacuten y Versiones

Si usted ha escrito programas con anterioridad seguramente le resultaraacute familiar la historiade Juan Loacutepez programador

Ayer como a las 1000pm mi programa funcionabaperfectamente Estaba yo haciendo cambios pequentildeos nada maacutespara limpiar el coacutedigo y me quedeacute hasta las 2 de la mantildeanahaciendo mejoras esteacuteticas pequentildeitas

Ahora son las 700am y tengo una demostracioacuten con el cliente enuna hora iexcliexcliexcly el programa no funciona No se que le hice peroojalaacute hubiera hecho una copia a las 1000pm

Este es uno de los muchos motivos por los que todo programador necesita un sistema decontrol de versiones Con un sistema de control de versiones nuestro hipoteacutetico Juan Loacutepezpodriacutea haber vuelto a la versioacuten que funcionaba perfectamente a las 8 de la noche y nohubiera perdido el cliente

La otra ventaja de un sistema de control de versiones es la posibilidad de comparar Con unsistema de control de versiones Juan hubiera podido hacer una comparacioacuten de losarchivos de su versioacuten con la versioacuten de las ocho de la noche para ver uacutenicamente lasdiferencias Como soacutelo necesitariacutea examinar las diferencias podriacutea haber encontrado elerror raacutepidamente y no tendriacutea que perder muchos de sus cambios esteacuteticos para recuperarel funcionamiento de su programa

Subversion

En este curso utilizaremos el sistema de control de versiones llamado subversionSubversion es un sistema disentildeado para reemplazar otro sistema de control de versionesllamado CVS CVS es el sistema de control de versiones usado en gran parte del mundo dela programacioacuten de fuente abierta Varios de los comandos que utilizaremos aquiacute tambieacutenson vaacutelidos en CVS

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 24: Tutorial de Ruby on Rails

Instalacioacuten en Unix

Si usted estaacute en un sistema Unix primero revise su versioacuten de subversion - algunasdistribuciones de Unix ya lo tienen Trate de ejecutar svn --version para ver si el programaresponde SI no lo tiene puede descargar los coacutedigos fuentes o los programas binarios de lapaacutegina de web de subversion Una vez instalado y configurado puede usted continuar paracrear su repositorio

Instalacioacuten en Windows

Para los usuarios de Windows hay dos opciones Usted puede utilizar los binarios de liacuteneade comando o una extensioacuten para Windows Explorer llamada TortoiseSVN que leproporcionaraacute menuacutes de contexto Recuerde que todas las demaacutes plataformas utilizan liacuteneade comando Este capiacutetulo explica coacutemo utilizar la liacutenea de comando En tortoiseSVN estonormalmente quiere decir hacer click con el botoacuten derecho en Windows y seleccionar elcomando con el mismo nombre en el menuacute de contexto

Creando un Repositorio

Un repositorio es un aacuterea en su sistema donde el sistema de control de versiones va aguardar su programa Su programa se guarda en una serie de archivos que guardan toda lahistoria de su programa Usted puede accesar toda la historia de las versiones de suprograma

Para crear un repositorio en subversion usted puede utilizar el comando svnadmin create

$ svnadmin create datosrepositoriosdirecciones

Esto crearaacute un repositorio llamado direcciones en el directorio datosrepositorio (que primerodebe existir) De preferencia (pero no obligatoriamente) usted debe hacer esto en unservidor para que se pueda conectar a el repositorio desde otras maacutequinas

Importando nuestro coacutedigo

Ahora que su repositorio ha sido creado podemos importar nuestro contenido Conanterioridad hemos creado una aplicacioacuten de rails que va a ser una libreta de direcciones ycreamos nuestro modelo de personas junto con el andamiaje Todo funciona bien hastaahora asiacute que lo que queremos es que esta sea la primera revisioacuten de nuestro programaAsiacute que importamos nuestro coacutedigo fuente del programa de direcciones especificando dondevive nuestro archivo

$ cd direcciones$ svn import filedatosrepositoriosdirecciones

iquestPorqueacute fileSubversion utiliza URNs para especificar donde vivesu repositorio Cuando usted utiliza svn sin unservidor el prefijo es file para acceder al sistemade archivos local En un ambiente multiusuario estiacutepico utilizar urns con http o ssh

A continuacioacuten svn abriraacute un editor de textos (en Unix el editor de textos es tiacutepicamente vi oel editor especificado en la variable $EDITOR) que contiene lo siguiente

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 25: Tutorial de Ruby on Rails

--This line and those below will be ignored--

A

La A junto al punto decimal quiere decir que estamos Antildeadiendo el directorio actual(representado por un punto) Es la manera en la que svn nos dice que va a ocurrir una vezque salgamos del editor de textos El motivo por el cual el editor de textos es mostrado espara que usted describa los cambios que le ocurrieron al repositorio (para el archivohistoacuterico)

Usted ahora puede escribir una descripcioacuten de lo que le estaacute haciendo al repositorio En estecaso estamos apenas comenzando asiacute que escribimos algo como lo siguiente

Importando el sistema de direcciones

--This line and those below will be ignored--

A

Ahora guarde el archivo y salga del editor A continuacioacuten veraacute que subversion antildeade todoslos archivos en su directorio al repositorio

Adding test

Adding testunit

Adding testunitpersona_testrb

Adding testtest_helperrb

Adding testfunctional

Adding testfunctionalpersonas_controller_testrb

Adding testfixtures

Adding testfixturespersonasyml

Adding testmocks

Adding testmockstest

Adding testmocksdevelopment

Adding app

Adding apphelpers

Adding apphelpersapplication_helperrb

Adding apphelperspersonas_helperrb

Adding appmodels

Adding appmodelspersonarb

Adding appcontrollers

Adding publicfaviconico

Committed revision 1

Nuestro repositorio ahora ha sido importado de este directorio Ahora necesitamossincronizar con el repositorio para que pueda mantener nuestros cambios Para hacer esonecesitamos primero jalar una copia que provenga del repositorio asiacute que cambiamos elnombre del directorio de nuestro programa (lo borraremos despueacutes que nos aseguremosque todo funciona bien) y ejecutamos el comando svn checkout para que el sistema utilicenuestro repositorio

$ cd

$ mv direcciones direccionesborrame

$ svn checkout filedatosrepositoriosdirecciones

A direccionestest

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 26: Tutorial de Ruby on Rails

A direccionestestunit

A direccionestestunitpersona_testrb

A direccionestesttest_helperrb

A direccionestestfunctional

A direccionestestfunctionalpersonas_controller_testrb

A direccionestestfixtures

A direccionestestfixturespersonasyml

A direccionestestmocks

A direccionestestmockstest

A direccionestestmocksdevelopment

Checked out revision 1

$ cd direcciones

Modificando Archivos

Ahora tenemos una copia que proviene del repositorio Esta copia seraacute actualizada cuandonosotros ejecutemos el comando svn commit desde el directorio de direcciones Podemosactualizar subdirectorios independientemente depende de donde ejecutemos el comandocommit Ademaacutes cambios a varios archivos en el repositorio se realizan atoacutemicamente (setoman en cuenta como uno) Por ejemplo haga algunos cambios a su archivodocREADME_FOR_APP con un editor de texto (este archivo es uacutetil para describir de que setrata su programa y como instalarlo) y despueacutes ejecute svn commit

$ svn commit

Ahora veraacute que su editor abre y muestra que ha habido un cambio al archivo

--This line and those below will be ignored--

M docREADME_FOR_APP

Escriba de que se tratoacute el cambio (por ejemplo Mejor explicacioacuten de nuestro programa) ysalga del editor Subversion guardaraacute el cambio

Sending docREADME_FOR_APP

Transmitting file data

Committed revision 2

Ahora el repositorio se encuentra en la revisioacuten 2

iquestQueacute significan A y MSubversion utiliza letras para explicarle queacute le ocurrea los archivos Las letras son como sigue

A Este archivo ha sido antildeadido (Added)M Este archivo ha sido modificado (Modified)D Este archivo ha sido elimidado (Deleted)

Historial de un archivo

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 27: Tutorial de Ruby on Rails

Para ver la historia de un archivo utilice el comando svn log

$ svn log docREADME_FOR_APP----------------------------------------------------------

--------------r2 | Owner | 2006-01-21 153914 -0800 (Sat 21 Jan 2006) | 2

lines

Mejor explicacion del programa

----------------------------------------------------------

--------------r1 | Owner | 2006-01-21 152801 -0800 (Sat 21 Jan 2006) | 3

lines

Importando el sistema de direcciones

----------------------------------------------------------

--------------

El sistema le explica los cambios que incluyeron este archivo

Antildeadiendo y eliminando archivos

Cuando usted antildeade y elimina archivos dentro de su sistema el sistema de control deversiones no efectuacutea los cambios hasta que usted especifique el comando svn add o svnrm (antildeadir y eliminar respectivamente) Asiacute usted no se necesita preocupar en eliminar unarchivo accidentalmente y de la misma manera no antildeadiraacute un archivo por error ensuciandola historia de su repositorio

Por ejemplo hagamos un archivo de prueba en el directorio doc Digamos que su nombrees pruebatxt

$ echo Hola como estas gt docpruebatxt

$ svn add docpruebatxt

A docpruebatxt

$ svn commit

Adding docpruebatxt

Transmitting file data

Committed revision 3

Ahora lo podemos eliminar

$ svn rm docpruebatxt

D docpruebatxt

$ svn commit

Deleting docpruebatxt

Committed revision 4

Actualizando el Repositorio

Otros programadores (o usted mismo en otra computadora) pueden cambiar su repositorioAl principio de cada sesioacuten de trabajo usted puede ejecutar el comando svn update parasincronizar de nuevo con el repositorio

$ svn update

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 28: Tutorial de Ruby on Rails

U docREADME_FOR_APP

En este ejemplo alguien cambioacute README_FOR_APP y ahora ya tengo sus cambios

Comparando versiones

Usted puede comparar versiones utilizando el comando svn diff Si usted no especificasoacutelo el nombre del archivo el sistema compararaacute la copia del archivo en su disco duro conla copia maacutes nueva del repositorio

Por ejemplo algunos cambios a la versioacuten en disco duro de mi docREADME_FOR_APPAhora ejecutareacute svn diff

$ svn diff docREADME_FOR_APP

Index docREADME_FOR_APP===================================================================

--- docREADME_FOR_APP (revision 2)

+++ docREADME_FOR_APP (working copy)

-12 +13

-Programa de ejemplo para el curso de rails

+Esta es una nueva liacutenea

En este listado las liacuteneas que se eliminaron comienzan con el signo de menos y las que seantildeadieron con el signo de maacutes Las arrobas me dicen aproximadamente donde (liacutenea ycolumna) se encuentra el cambio

Finalmente no quiero quedarme con este cambio asiacute que mejor ejecuto svn revert para quemi copia se elimine y se reemplace con la del repositorio

$ svn revert docREADME_FOR_APPReverted docREADME_FOR_APP

Esto es soacutelo una introduccioacuten y subversion tiene muchos otros comandos Le recomiendoque revise la documentacioacuten y aprenda lo maacutes que pueda de este excelente sistema

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 29: Tutorial de Ruby on Rails

9 Pruebas de Unidad

Preparando un Ambiente de Prueba

Como vimos cuando estabamos configurando la base de datos usted necesita tener unabase de datos separada para prueba Si usted ha seguido el tutorial y no creoacute una base dedatos de prueba la puede crear ahora (vaciacutea) simplemente ejecutando el comando CREATEDATABASE direcciones_test (o el nombre que tenga su base de datos)

Probando el Directorio

Ahora siacute estamos listos para crear las pruebas de nuestro directorio Rails ya antildeadioacute algunaspruebas a nuestro sistema esqueleto asiacute que intentaremos ejecutarlas

$ rake(in homedavidplaydirecciones)rubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testunitpersona_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 02 seconds

1 tests 1 assertions 0 failures 0 errorsrubybinruby -Ilibtest rubylibrubygems18gemsrake-062librakerake_test_loaderrb testfunctionalpersonas_controller_testrbLoaded suite rubylibrubygems18gemsrake-062librakerake_test_loaderStartedFinished in 0751 seconds

8 tests 28 assertions 0 failures 0 errors

iexclQueacute bueno pasamos iquestPero queacute se proboacute Veamos las pruebas que tenemos Losprogramas en el directorio test son

$ find test -name rbtestfunctionalpersonas_controller_testrbtesttest_helperrbtestunitpersona_testrb

Pruebas de Unidad vs Funcionales

En el esqueleto creado por rails las pruebas se dividen en pruebas de unidad (queidealmente prueban cada meacutetodo de nuestro programa) y pruebas funcionales que pruebanque su programa haga lo que usted espera

En general las pruebas funcionales prueban el controlador y las pruebas de unidad pruebanel modelo y las clases de soporte

Cuando usted creoacute el moacutedulo MVC de personas el generador de coacutedigo preparoacute esqueletos

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 30: Tutorial de Ruby on Rails

para sus pruebas de unidad

Para ver de queacute se compone una prueba baacutesica veamos el archivo testunitpersona_testrb

require Filedirname(__FILE__) + test_helper

class PersonaTest lt TestUnitTestCase fixtures personas

Replace this with your real tests def test_truth assert_kind_of Persona personas(first) endend

Una prueba de unidad en ruby es una clase que hereda de TestUnitTestCase Dentro deesta clase nosotros escribimos las pruebas

Adornos (Fixtures)

A veces nuestras pruebas de unidad requieren de registros de prueba en la base de datosEn terminologiacutea rails estos registros se llaman fixtures o adornos Se llaman asiacute porqueson uacutetiles primariamente para que la prueba tenga datos con los cuales trabajar

Los adornos para nuestra tabla se encuentran en el folder testfixturespersonasymlComo podraacute imaginar cuando creamos nuesto moacutedulo utilizando el generador rails nos hizoel favor de incluir este archivo de adorno para la tabla

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlfirst id 1another id 2

Lo que tenemos que hacer ahora es antildeadir nuestros datos iniciales El llenado de losadornos es muy sencillo y se hace de acuerdo a la descripcioacuten de la tabla que disentildeamoscon anterioridad

Read about fixtures at httparrubyonrailsorgclassesFixtureshtmlpersonaje_novela id 1 nombre Alonso apellido_paterno Quijano apellido_materno Cervantes desplegar Alonso Quijano sexo Hombre notas Nacio en un lugar de la Mancha de cuyo nombre no quiero acordarme

actor_famoso id 2 nombre Pedro apellido_paterno Infante apellido_materno Cruz desplegar Pedro Infante sexo Hombre notas El Idolo de Guamuchil

Note que en el formato YML podemos nombrar nuestros registros para describir su

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 31: Tutorial de Ruby on Rails

naturaleza que nos ayudaraacute para que nuestras pruebas sean maacutes claras En este casocambiamos los nombres first y another por personaje_novela y actor_famoso Comocambiamos el nombre de nuestro primer registro nuestro meacutetodo test_truth en el listadoanterior tambieacuten necesita cambiar

Utilizando Adornos

Estas pruebas son un poco triviales pero hagamos un par de pruebas de unidad paracomprobar que esto funcione

def test_actor_famoso actorazo = personas(actor_famoso) assert_equal Infante actorazoapellido_paternoend

Desarrollo Basado en Pruebas

Con anterioridad vimos brevemente que Ruby soporta Desarrollo basado en Pruebas perono explicamos especiacuteficamte la mecaacutenica del desarrollo basado en pruebas con un ejemploAhora veremos un ejemplo praacutectico de eacuteste desarrollo que le permitiraacute comprender elproceso de pensamiento que utiliza un desarrollador que se basa en pruebas

Cambio de Metodologiacutea

Lo que vamos a presentar a continuacioacuten representa un cambio demetodologiacutea y tren de pensamiento de lo que muchosdesarrolladores estaacuten acostumbrados

Acostumbrarse a probar primero no es sencillo pero vale la penaintentarlo

Apellidos en Espantildeol

En la lengua de Cervantes los apellidos tienen reglas un poco especiales Necesitamosimplementar un meacutetodo llamado apellidos que desplegaraacute los apellidos de la siguientemanera

Si hay apellido ambos apellidos Paterno Materno (separados por espacios)Si hay apellido paterno uacutenicamente PaternoSi no hay apellido paterno Materno

Como estamos desarrollando basados en nuestras pruebas primero tenemos que prepararuna prueba que falle y datos de prueba

Preparando Datos de Prueba

Para los datos de prueba antildeadimos a personasyml registros que cubran los casosadecuados

sin_appellidos id 3 nombre Maria desplegar Maria sexo Mujer

solo_apellido_paterno id 4

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 32: Tutorial de Ruby on Rails

nombre Juan apellido_paterno Gomez

solo_apellido_materno id 5 nombre Pedro apellido_materno Paramo ambos_apellidos id 6 nombre Juan apellido_materno Torres apellido_paterno Mendoza

Coacutedigo de Prueba

Ahora que tenemos informacioacuten de prueba podemos crear nuestras pruebas Todaviacutea notenemos el coacutedigo pero sabemos lo que esperamos en los diferentes casos Asiacute queantildeadimos a nuestro archivo testunitpersona_testrb los meacutetodos de prueba quenecesitamos Comenzamos los meacutetodos con test para que la clase TestCase los ejecute

class PersonaTest lt TestUnitTestCase fixtures personas

def test_ambos_apellidos bien_nacido = personas(ambos_apellidos) assert_equal( bien_nacidoapellido_paterno+ +bien_nacidoapellido_materno bien_nacidoapellidos )

end

def test_solo_paterno persona = personas(solo_apellido_paterno) assert_equal( personaapellido_paterno personaapellidos ) end

def test_solo_materno persona = personas(solo_apellido_materno) assert_equal( personaapellido_materno personaapellidos ) end

def test_sin_apellidos persona = personas(sin_apellidos) assert_equal( personaapellidos ) end

end

Ahora podemos escribir un metodo cabo (un meacutetodo baacutesicamente vaciacuteo) que ataremoscon el coacutedigo adecuado maacutes tarde En nuestro archivo appmodelspersonarb

def apellidos end

La Prueba que Falla

Ahora cuando ejecutemos rake veremos que la uacutenica prueba que funciona es la desin_apellidos Funciona de pura casualidad porque la implementacioacuten de nuestro meacutetodoestaacute vacia

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 33: Tutorial de Ruby on Rails

$ rake TEST=testunitpersona_testrb(in cygdrivechomedavidplaydirecciones)usrbinruby -Ilibtest usrlibrubygems18gemsrake-070librakerake_test_loaderrb testunitpersona_testrbLoaded suite usrlibrubygems18gemsrake-070librakerake_test_loaderStartedFFFFinished in 0611 seconds

1) Failuretest_ambos_apellidos(PersonaTest) [testunitpersona_testrb13]ltMendoza Torresgt expected but wasltgt

2) Failuretest_solo_materno(PersonaTest) [testunitpersona_testrb24]ltnilgt expected but wasltgt

3) Failuretest_solo_paterno(PersonaTest) [testunitpersona_testrb19]ltGomezgt expected but wasltgt

5 tests 5 assertions 3 failures 0 errorsrake abortedTest failures

(See full trace by running task with --trace)

Note que podemos ejecutar soacutelo una prueba simplementeantildeadiendo el nombre del archivo ruby que contiene su prueba

Pero lo importante que hay que tener en cuenta es que gracias a nuestras pruebas deunidad (que fueron creadas antes del coacutedigo basadas en el disentildeo) tenemos las siguientesventajas

Sabemos en todo momento queacute condiciones estaacuten cubiertas por nuestro coacutedigo (gracias a que losnombres de las pruebas son descriptivos)Tenemos una buena idea de queacute tanto avance hemos hecho en nuestro coacutedigo (por ejemplo en estemomento una de cuatro pruebas pasan)Otras personas pueden comenzar a integrar con nuestro meacutetodo apellido y nuestras pruebas manejanlas expectativas Esto es uacutetil en especial cuando usted trabaja en equipoUsted puede antildeadir el comando rake a un proceso nocturno para saber cuando hay cambios querompen las pruebas Cuando el coacutedigo cambie en una manera que no es compatible con el resto delsistema sus pruebas se romperaacuten y usted lo sabraacute antes de que se enteren sus usuariosCuando usted descubra alguacuten problema causado por liacutemites (valores fuera de lo comuacuten) puede antildeadirotra prueba al aacuterea adecuada y despueacutes correjir el error lo cual le proporciona una regresioacutenautomaacutetica

Implementando la funcioacuten

Finalmente podemos implementar la funcioacuten para los apellidos y continuar arreglandoproblemas hasta que nuestro comando de prueba muestre el resultado deseado

$ rake TEST=testunitpersona_testrb

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 34: Tutorial de Ruby on Rails

5 tests 5 assertions 0 failures 0 errors

Y ahora si podemos decir que nuestro soporte de apellidos en espantildeol estaacute completo ytenemos cinco pruebas que lo demuestran

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 35: Tutorial de Ruby on Rails

10 Teoriacutea de Objetos

ObjetosUn objeto es un tipo de datos que incorpora datos y coacutedigo (comportamiento) en un solopaquete Aacutentes de la era de la orientacion a objetos el coacutedigo y los datos eran dos cosasseparadas La orientacioacuten por objetos nos permite representar de un modo mucho maacutesconveniente al mundo real

iquestCoacutemo podemos modelar un objeto del mundo real con objetos de computadora Veamosun ejemplo

Ejemplo de un Objeto

Supongamos que estamos haciendo un juego acerca de un Acuario Para este juegoqueremos disentildear un Bonito Delfiacuten que va a brincar con el aro y jugar con la pelota peroqueremos en el futuro extender el juego para cualquier tipo de animal marino porque va aser una simulacioacuten bien picuda Tal como en el mundo real necesitamos comenzar con unobjeto llamado pescado (Para los amantes de la biologia Ya se que el delfiacuten es unmamiacutefero y no un pescado pero eacuteste es un ejemplo) El objeto pescado tiene sus datoscomo son alto largo peso y color Pero el pescado tambien puede hacer otras cosas comopor ejemplo nadar y sumergirse Entonces primero hacemos nuestro objeto pescado quetiene la siguiente forma

class Pescado

def Pescado

largo = 200

alto = 50

ancho = 50

peso = 350

end

def nadar

Codigo

end

def sumergirse

Codigo

end

end

Este coacutedigo le dice a la computadora Pescado es una clase (una clase es una definicioacuten deun objeto) Tiene los campos Largo Alto Ancho y Peso que son nuacutemeros de punto flotanteSus meacutetodos puacuteblicos (lo que todo mundo sabe que un pez puede hacer) son Nadar ySumergirse

Si esto parece complejo por favor sigan leyendo Muy pronto todo quedaraacute claro

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 36: Tutorial de Ruby on Rails

Ahora el Delfiacuten He decidido para este ejemplo que hay dos clases de delfines losentrenados y los salvajes (no entrenados) Asi que comencemos con el delfin entrenado

class Delfin lt Pescado

def tomar_aire

Codigo

end

def haz_ruido

Codigo

endend

Ahora bien este codigo le dice a la computadora El Delfin es una clase que heredade Pescado (o Un Delfin es un Pescado) Esto quiere decir que un Delfin puede hacertodo lo que un pescado puede hacer (tiene largo alto ancho peso y ademaacutes puedenadar y sumergirse) Entonces yo ya termineacute mi delfin y no tuve que implementar de nuevolas funciones para nadar y sumergirse que el pescado (y ahora tambien el delfin) puedehacer Ahora vamos a entrar en la materia del jueguito el delfin entrenado

class DelfinEntrenado lt Delfin

def juega_con_pelota(segundos)

Codigo

end

def brinca_el_aro(circunferencia)

Codigo

end

end

El DelfinEntrenado es una clase que hereda no de Pescado sino de Delfin (o Un delfiacutenentrenado sigue siendo un delfin pero) Al igual que la vez anterior un delfiacuten entrenadopuede hacer todo lo que un delfin puede hacer pero ademaacutes puede jugar con pelota ybrincar el aro

iquestPorqueacute hacer tres objetos nada maacutes para representar un delfiacuten Supongamos que ahoraquiero hacer un tiburoacuten

class Tiburon lt Pescado

def Tiburon

dientes = 200

bocon = true

come_hombres = false

end

def enojate

end

def come_persona(sabroso)

end

def espanta_visitantes

end

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 37: Tutorial de Ruby on Rails

end

Gracias a la orientacioacuten a objetos ahora estoy re-utilizando el coacutedigo que useacute paraimplementar mi delfiacuten Ahora si mantildeana descubro que los pescados pueden nadar de unamanera especial o quiero hacer la simulacioacuten detallada y quiero hacer que hagan algo maacutescomo nacer y morirse todos los objetos de tipo pescado (tiburon delfiacuten delfiacuten entrenadopez dorado) van a nacer y morir igual que el pescado porque la implementacioacuten aplica altipo y a todos los tipos de la misma clase Ahora bien la jerarquiacutea de los objetos quehemos hecho es como sigue

Object

+----- Pescado

|

+----- Delfin

| |

| +----- Delfin Entrenado

| +----- Tiburon

La jerarquiacutea de objetos es una especie de aacuterbol genealoacutegico que nos dice queacute objetos sederivan de otros objetos Como conceptualizamos esta jerarquiacutea Es de hecho bastantesencillo una vez que nos acostumbramos al aacuterbol Por ejemplo supongamos que queremossaber que interfaces soporta el Delfiacuten Entrenado Leemos todos los padres de lasiguiente manera Un Delfin ES UN Pescado que ES UN Objeto Esto quiere decir que unobjeto de la clase DelfinEntrenado soporta todas los metodos que objetos de la clase Delfiny de la clase Pescado

Tipos en Ruby

Los lenguajes orientados a objetos son tiacutepicamente de tipos fuertes o tipos deacutebiles

Un lenguaje de tipos fuertes revisa las asignaciones de valores en el programa para ver sison del mismo tipo antes de la ejecucioacuten (al tiempo de compilar) Un lenguaje de tiposdeacutebiles soacutelo revisa al tiempo de ejecucioacuten

La evaluacioacuten de tipos en ruby es un poco especial En ruby los tipos estaacuten definidos comolas capacidades de un objeto en vez de estar definidos arbitrariamente por naturaleza Enotros lenguajes esto se llama polimorfismo y lo consiguen mediante interfaces En Ruby lasinerfaces no son necesarias

Los rubyistas le llaman evaluacioacuten tipo Pato por el dicho en Ingleacutes que va Si caminacomo un pato y habla como un pato es un pato

Esto quiere decir que ruby intentaraacute ejecutar los meacutetodos de su objeto incluso cuando lostiacutepos sean diferentes En nuestro ejemplo anterior si le antildeadieramos al Tiburoacuten un meacutetodobrinca_el_aro

class Tiburon lt Pescado

def brinca_el_aro(circunferencia)

endend

Nuestro coacutedigo intentariacutea ejecutarlo incluso cuando fueacute disentildeado para un DelfiacutenEntrenado

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 38: Tutorial de Ruby on Rails

11 Mapeo de Objetos a Relaciones

El Modelo Relacional vs El Modelo de Objetos

Las bases de datos SQL funcionan en modo relacional Esto quiere decir que utilizan unaMatriz de celdas para representar los datos En cada rengloacuten de una matriz existe unregistro individual Cada columna de la matriz representa uno de los valores de ese registroy tiene un tipo especiacutefico (numerico caracteres etcetera)

Tabla Personas

id Nombre Apellido Sexo Nacido En1 Elvis Presley M Nashville Tenesee2 Albert Einstein M Wuumlrttemberg Alemania

En el modelo relacional dos tablas pueden estar relacionadas a traves de una clave deidentidad entre otras cosas para poder representar valores repetidos o valores que nopertenecen a la naturaleza de lo que representa la tabla

Tabla Telefonos

id persona_id Pais Area Telefono1 2 52 777 334-23402 2 49 30 495-20303 1 1 615 394-2304

A traves de una de las columnas la tabla se relaciona

Sin embargo en el modelo de objetos los registros son instancias de un tipo de objeto Enel mundo de programacion orientada a objetos no hay diferencia innata entre un tipo que esparte del lenguaje (por ejemplo String) y un tipo que representa registros para la base dedatos (como Persona o Telefono) Ademaacutes en el modelo de objetos los tipos tienenreferencias directas

Personanombre Stringapellido StringsexoMasculino booleannacidoEn Stringtelefonos Telefono[]

pais Stringarea Stringtelefono String

Mapeo de objetos quiere decir crear una manera de convertir un diagrama de objetos paraque pueda ser automaacuteticamente mantenido por la base de datos Los sistemas de mapeo deobjetos tiacutepicamente saben como mapear los tipos innatos del lenguaje como string e intEstos tipos son especiales ya que son tipos de columnas en el mundo de las bases de datosrelacionales

>

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 39: Tutorial de Ruby on Rails

Aproximaciones al problema

Ahora que sabemos que el mapeo de objetos consiste en crear un mapa de los tipos deobjetos a las tablas columnas y tipos de datos podemos imaginar dos tipos deaproximaciones

De Objeto a Tabla- Utilizando este meacutetodo usted crea el objeto primero y despues antildeade metadatosal objeto (ya sea como comentarios con alguacuten archivo de configuracioacuten o con definiciones en el objetomismo) que especifican los nombres de archivos y el estilo de mapeo que se utilizaraacute

Este meacutetodo es preferido por los arquitectos de software ya que permite disentildear el modelo de objetosindependientemente del sistema que se utilice para guardar estos objetos

Aunque tiene la ventaja de que produce un disentildeo aparentemente maacutes limpio desde el punto de vistade los arquitectos el problema de estos disentildeos es que a los administradores de bases de datos no lesgusta porque los sistemas disentildeados asiacute resultan bastante lentos para accesar la base de datos

De Tabla a Objeto- Este meacutetodo es favorecido principalmente por los administradores de bases dedatos porque permite optimizar las tablas desde la fase de disentildeo Una implementacioacuten de este meacutetodoes la libreriacutea Hibernate (para Java y Net)

Aunque tiene la ventaja de que produce un disentildeo maacutes eficiente el problema de este meacutetodo es quepuede provocar que las definiciones semaacutenticas de los objetos parezcan arbitrarias

ActiveRecord

Ruby utiliza la libreriacutea ActiveRecord para mapear objetos a relaciones Sus clases heredande ActiveRecordBase Si usted ya ha seguido el tutorial acerca de coacutemo crear un moacuteduloMVC usted sabraacute que el meacutetodo que utiliza es el meacutetodo de tabla a objeto Sin embargousted puede cambiarle de nombre a las columnas y las tablas para crear un modelosemaacutentico maacutes claro

Definiendo nombres de columnas y tablas

En ActiveRecord los nombres de las columnas se pueden cambiar redefiniendo el meacutetodotable_name() del objeto de la manera siguiente

class Personas lt ActiveRecordBase def selftable_name() GENTES end end

Para cambiar nombres de columnas (y para hacer campos calculados) usted puedesimplemente definir meacutetodos para obtener y cambiar los valores en un patroacuten de fachada

class Personas lt ActiveRecordBase

def nombre() read_attribute(G_NOMBRE) end def nombre=(elnombre) write_attribute(G_NOMBRE elnombre) end def nombre_completo() nombre() + + apellido() end end

En este ejemplo el programador ha antildeadido una fachada para que la columna

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 40: Tutorial de Ruby on Rails

G_NOMBRE responda a la propiedad nombre en el objeto Ademaacutes se ha antildeadido unapropiedad nombre_completo que formatea el nombre y apellido

Nota Si usted tiene control del disentildeo de base de datos asiacute comode los objetos es maacutes recomendable utilizar los nombres de lastablas y columnas de tal manera que coacutedigo de mapeo no seanecesario como lo vioacute en el tutorial de moacutedulo MVC

De esta manera su coacutedigo es maacutes sencillo de mantener

Definiendo Relaciones Entre Objetos

Vimos hace unos momentos que en el modelo relacional las relaciones entre dos tipos sonrepresentadas utilizando columnas relacionadas Ahora veremos este y varios otros tipos derelaciones

Relaciones Circulares

Las relaciones de pertenencia se representan con has_one o con has_many lo cual lepermite especificar que la relacioacuten es de uno a uno o de uno a muchos respectivamente Larelacioacuten opuesta se puede representar con belongs_to en la clase de destino El resultadose ve muy natural

class Persona lt ActiveRecordBase has_one detalle has_many telefonoend

class Detalle lt ActiveRecordBase belongs_to personaend

class Telefono lt ActiveRecordBase belongs_to personaend

Esto requiere que los siguientes nombres de columnas por defecto

Tabla Columnapersona iddetalles persona_idtelefonos persona_id

Por supuesto si es necesario usted puede cambiar los nombres de columnas por defectopor medio de modificar las opciones de belongs_to En el siguiente ejemplo cambiaremos elnombre de la columna que conecta a la persona en la clase de detalles

class Detalle lt ActiveRecordBase belongs_to persona foreign_key=gthumano_idend

Relaciones Circulares

La posibilidad de cambiar opciones en belongs_to permite entre otras cosas crearrelaciones circulares por ejemplo

class Persona lt ActiveRecordBase

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 41: Tutorial de Ruby on Rails

belongs_to padre class_name=gtPersona foreign_key=gtpadre_id belongs_to madre class_name=gtPersona foreign_key=gtmadre_id

end

Asociaciones con tabla de Pivote

Un tipo de relaciones muy uacutetil en el mundo de SQL es la relacioacuten de muchos a muchos locual se logra con lo que se llama una tabla de pivote Supongamos que tenemos unarelacioacuten de Personas y Compantildeias Una persona puede ser cliente de varias compantildeiacuteas Ylas compantildeiacuteas pueden tener varios clientes La tabla de pivote es como sigue

companias_personas tipopersona_id intcompania_id int

Esta relacioacuten se puede representar con has_and_belongs_to_many de la manera siguiente

class Compania lt ActiveRecordBase has_and_belongs_to_many personasend

class Persona lt ActiveRecordBase has_and_belongs_to_many companiasend

Definiendo Jerarquiacuteas de Objetos y Herencia

Las jerarquiacuteas de objetos en sistemas de mapeo relacional se pueden representarautomaacuteticamente con una sola tabla Para lograrlo su tabla necesita tener un campollamado type que representaraacute el tipo del objeto y los campos de la jerarquiacutea completadeben estar definidos

Por ejemplo para representar los campos de la jerarquiacutea de objetos de nuestro ejemplo enla seccioacuten teoriacutea de objetos (una jerarquiacutea de pescado-gtTiburoacuten-gtDelfiacuten) podriacuteamos definiruna tabla como sigue

Tabla Pescados

nombre tipoid integertype varcharnombre varcharlargo integerancho integerancho integerpeso integerPropiedades del Delfiacuten

mamarias integerPropiedades del Tiburoacuten

come_hombres booleandientes integerbocon boolea

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 42: Tutorial de Ruby on Rails

Con este tipo de tabla ActiveRecord simplemente utilizaraacute los campos adecuados yregresaraacute el tipo adecuado dependiendo del campo type

Aacuterboles

Un aacuterbol es una representacioacuten donde los objetos tienen un soacutelo padre Para definir un aacuterbolen ActiveRecord utilizamos el coacutedigo acts_as_tree y definimos un campo llamado parent_idque permita valores nulos

Tabla Categorias

nombre tipoid integerparent_id integer NULLorden integernombre varchar

Con esto podemos definir la tabla e incluso podemos utilizar opciones para mantener elorden de los nodos hijos asiacute como para mantener una cuenta de hijos

class Categoria lt ActiveRecordBase acts_as_tree order =gt orden counter_cache =gt true end

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 43: Tutorial de Ruby on Rails

12 Modificando el Moacutedulo Generado

Tenemos nuestro coacutedigo generado pero maacutes que nada esto fueacute para que nuestros usuarioslo vieran e hicieran algunas decisiones en cuanto a los campos que faltan etceacutetera Ahoraanalizaremos coacutemo funciona una vista para comenzar a hacer las modificaciones

Vistas en nuestro moacutedulo

Cuando generamos el moacutedulo de personas se generoacute un moacutedulo de controlador y variasvistas Repasemos lo que fueacute generado

appviewslayoutspersonasrhtml appviewspersonas_formrhtml appviewspersonaseditrhtml appviewspersonaslistrhtml appviewspersonasnewrhtml appviewspersonasshowrhtml

Recordemos que ruby utiliza convencioacuten en vez de configuracioacuten La vista para elmoacutedulo de personas siempre comenzaraacute en el esquema (layout) de personas Cuandovemos el texto dentro del archivo layoutspersonasrhtml veremos lo siguiente

lthtmlgtltheadgt lttitlegtPersonas lt= controlleraction_name gtlttitlegt lt= stylesheet_link_tag scaffold gtltheadgtltbodygt

ltp style=color greengtlt= flash[notice] gt

lt= content_for_layout gt

ltbodygtlthtmlgt

Un archivo RHTML es una combinacioacuten de HTML y ruby El coacutedigo ruby vive dentro de losdelimitadores lt gt o lt= gt si desea el resultado de una funcioacuten desplegado en el HTML

Veamos la uacuteltima parte del esquema de personas

lt= content_for_layout gt

Este comando le dice a rails que es aquiacute donde puede insertar el contenido del esquema Elesquema es como un formato general para este controlador

Despachando peticiones en Rails

El resultado de una peticion a nuestra aplicacioacuten depende del URL Cuando un usuario pide

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 44: Tutorial de Ruby on Rails

httpmiservidorpersonalist Rails deduce que el controlador se llama persona y laaccioacuten dentro del controlador es list Asiacute que rails haraacute lo siguiente

Ejecutar el meacutetodo list en appcontrollerspersonas_controllerrb

Utilizar viewspersonaslistrhtml para evaluar la presentacioacuten de los resultados del meacutetodo listUna vez evaluados los resultados se ponen en una variable llamada content_for_layoutUtilizar viewslayoutspersonasrhtml como el esquema para desplegar los resultados del controladorEn alguacuten lugar de este esquema mostraremos la variable content_for_layout como vimos conanterioridad

Esto quiere decir que si usted desea cambiar de nombre al meacutetodo list para traducirlo alistar debe hacer lo siguiente

Cambiar de nombre al meacutetodo list en appcontrollerspersonas_controllerrb

Cambiar de nombre al archivo viewspersonaslistrhtml

Comandos con formularios

Gran parte de lo que hacemos en Rails es llenar formularios Los formularios en Rails soncompartidos utilizando el archivo _formrhtml Veamos una de las vistas que requieren elformulario appviewspersonaseditrhtml

lt= start_form_tag action =gt update id =gt persona gt lt= render partial =gt form gt lt= submit_tag Edit gtlt= end_form_tag gt

lt= link_to Show action =gt show id =gt persona gt |lt= link_to Back action =gt list gt

Note que el moacutedulo de edicion prepara la forma para que llame el comando update y despuesemite un contenido parcial llamado form Dentro del contenido parcial _formrhtmlpodemos ver lo siguiente

lt= error_messages_for persona gt

lt--[formpersona]--gt

ltpgtltamptlabel for=persona_nombregtNombreltlabelgt

lt= text_field persona nombre gtltpgt

(mas y mas campos)lt--[eoformpersona]--gt

Rails tiene comandos para todos los controles de forma del HTML y tien algunos controlesextra Cuando usted estudie el HTML generado podraacute hacer sus propios controlescomplejos

Parciales

Como lo hemos visto con el ejemplo de la forma los parciales son muy uacutetiles Un parcial esun fragmento de RHTML que usted puede re-utilizar en varios contextos ya sea en variosmeacutetodos en varios controladores o varias veces en la misma vista

Usted puede crear un parcial simplemente antildeadiendo el archivo (su nombre debe comenzarcon un simbolo de subrayado) y llamando el parcial con render partial=gtmiparcial (paraun archivo llamado _miparcialrhtml) Por defecto el parcial seraacute buscado dentro del

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 45: Tutorial de Ruby on Rails

directorio de la vista actual pero usted puede cambiar el directorio simplementemencionandolo por ejemplo render partial=gtdirectoriomiparcial (en este caso elarchivo seriacutea appviewsdirectorio_miparcialrhtml)

El parcial tendra acceso a todas las variables de instancia del controlador y la vista que lollamoacute

Ideas para usos de parciales

Ademaacutes de las formas he aquiacute algunos ejemplos para uso de parciales

Navegacioacuten En vez de repetir un area de navegacion comun por cada pagina usted puede llamar unparcial para la navegacion comunCabecerasPieceras Usted puede crear cabeceras y pieceras una sola vez y simplemente llamarlasdentro de sus esquemasRegistros complejos dentro de tablas Si usted necesita desplegar muchos registros y el tipo deregistro es muy complejo (digamos que tiene muchas clases y javascript que debe de funcionarperfectamente) puede crear un parcial para desplegar un registro individual y llamar el parcial dentro delcicloCanastas para compras Es importante que la canasta que muestra la orden en un programa decomercio sea uniforme En vez de repetir el coacutedigo usted puede llamar un parcial

Cambiando el Listado

Ahora hay que hacer que el listado se vea mejor Primero veamos el coacutedigo generado en viewspersonaslistrhtml (o listar si ya le cambioacute el nombre)

Leyendo el coacutedigo generado descubriremos el uso de metadata en las columnas de registrosde ActiveRecord

lttablegt lttrgt lt for column in Personacontent_columns gt ltthgtlt columnhuman_name gtltthgt lt end gt lttrgt

lt for persona in personas gt lttrgt lt for column in Personacontent_columns gt lttdgtlt= h personasend(columnname) gtlttdgt lt end gt lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttdgtlt link_to Edit action =gt edit id =gt persona gtlttdgt lttdgtlt link_to Destroy action =gt destroy id =gt persona confirm =gt Are you sure gtlttdgt lttrgtlt end gtlttablegt

Note que el coacutedigo generado es dinaacutemico Cuando usted antildeade columnas a su objetoPersona la tabla tendraacute esas columnas tambien Tambieacuten note que para crear un enlace aalguna accioacuten sobre la persona en cada rengloacuten se utiliza el comando link_to

Evidentemente esto soacutelamente funciona para prototipos raacutepidos porque el dinamismo soacuteloaplica a las columnas y no a los meacutetodos calculados (como el campo calculado apellidos)

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 46: Tutorial de Ruby on Rails

Asiacute que cambiamos el listado para que sea maacutes estaacutetico

lt for persona in personas gt lttrgt lttdgtlt= h personanombre gtlttdgt lttdgtlt= h personaapellidos gtlttdgt (mas campos) lttdgtlt link_to Show action =gt show id =gt persona gtlttdgt lttrgt

Obviamente es aquiacute donde usted puede hacer el HTML tan artiacutestico como quieraHablaremos de HTML y CSS maacutes tarde pero esto le da una buena base para comprendercoacutemo funciona la generacioacuten de vistas en Rails y coacutemo usted puede cambiar el HTMLgenerado y planear su sitio Por ahora cambie la tabla para que tenga soacutelo los registros queusted desee

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 47: Tutorial de Ruby on Rails

13 Buen Disentildeo con CSS

Con anterioridad mencionamos que Rails es parte del paradigma de disentildeo de aplicacionesde web 20 Esto quiere decir que el disentildeo de la paacutegina debe de seguir principios de disentildeode HTML modernos En este capiacutetulo veremos los principios e ideas que influencian eldisentildeo de Rails

Nota

Este no es un curso de CSS La idea es entenderporqueacute Rails y AJAX requieren de CSS y un disentildeolimpio Si no sabes CSS un buen lugar paracomenzar es el Tutorial de CSS de W3org

CSS - Hojas de Estilo de Cascada

Las hojas de estilo CSS le permiten separar el contenido de su paacutegina de la presentacioacuten dela misma Asimismo la capacidad de antildeadir maacutes de un estilo a su paacutegina web le permite

Cambiar su disentildeo visual sin cambiar su contenidoMantener su coacutedigo HTML y CSS limpio y claroAntildeadir y combinar elementos de disentildeo por referencia (sin incluirlos directamente en su archivo HTML)

Disentildeo Semaacutentico Rails y AJAX

Limpieza semaacutentica quiere decir claridad de propoacutesito dentro de nuestro coacutedigo Esto seobtiene

1 Manteniendo Nuestro coacutedigo HTML limpio y claro2 Antildeadiendo divisiones loacutegicas e identificadores de acuerdo con el propoacutesito de nuestra paacutegina

HTML Claro con CSS

Si la idea es crear tres paacuterrafos y un tiacutetulo el coacutedigo debe tener tres ltpgts y un lth3gt Antesde CSS los disentildeadores de HTML debiacutean poner muchos de sus paacuterrafos y tiacutetulos en tablaspara poderlos posicionar correctamente Un buen disentildeo semaacutentico evita usar tablas y otrasetiquetas cuyo uacutenico propoacutesito es forzar el estilo visual de la paacutegina Esto es porque lastablas obscurecen el propoacutesito del texto

Tablas y Disentildeo Semaacutentico

Antes del disentildeo semaacutentico las tablas se utilizabanmucho para posicionar su disentildeo con exactitud Unbuen disentildeo moderno soacutelo utiliza tablas paradesplegar datos tabulares como listas y hojas decaacutelculo (que era la razoacuten original de la existencia delas tablas en primer lugar)

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 48: Tutorial de Ruby on Rails

Divisiones e Identificadores

Una vez que nuestro disentildeo de HTML estaacute limpio podemos antildeadir etiquetas de division(ltdivgt) y attributos identificadores (id=) Basados en estos atributos usted puede definiruna estructura que le permite a Rails AJAX y otras herramientas manipular su HTML dentrodel navegador Por ejemplo dentro de nuestra libreta de direcciones podemos hacer losiguiente

ltdiv id=persona_detalle_contenedorgt lth1 class=titulo_detallegtEditar Personalth1gt ltform class=forma_personagt ltlabel for=persona_nombregtNombreltlabelgt ltinput name=persona_nombregtltinputgt ltdivgt

Esta claridad nos permite utilizar funciones de AJAX para reemplazar el contenido depersona_detalle_contenedor con una vista de detalle una vez que el usuario guarde laforma Como las divisiones en la estructura son claras es mucho maacutes sencillo cambiar lapaacutegina existente

Muchos de los conceptos de Rails y otras ayudas de desarrollo para web 20 se basan encambiar secciones de HTML sin refrescar la paacutegina completa

Herramientas de HTML Visuales

Las herramientas visuales de HTML tienden a insertar tablas yotros elementos no requeridos Cuando evaluacutee una herramientaque genere HTML para su uso personal verifique si el HTMLgenerado es semaacutentico con CSS y no contiene tablas Eviteherramientas que no puedan generar CSS o respetar la estructurasemaacutentica de su paacutegina

La mejor manera de aprender coacutemo hacer estos disentildeos es ver otros disentildeos limpios yexaminar sus fuentes de HTML He aquiacute algunos ejemplos de buen disentildeo

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13
Page 49: Tutorial de Ruby on Rails

14 Utilizando Helpers

HelpersUn Helper es un moacutedulo que ayuda a tus vistas definiendo funciones que ayudan a que tusvistas sean maacutes que nada HTML y no contengan demasiado coacutedigo En un sistema demodelo MVC la idea es que la vista (la V de MVC) sea tan simple como sea posible

Rails viene con varios Helpers y tu aplicacioacuten tiene un application_helper para que tengasayudas especiacuteficas a tu aplicacioacuten Normalmente los helpers producen contenido para elHTML or Javascript de tu aplicacioacuten

Helpers incluidos en Rails

Alguacutenos de los helpers maacutes uacutetiles incluidos en Rails incluyen

AssetTagHelper Crea HTML para imaacutegenes Javascripts y CSS Te permite definir servidores de webestaacuteticos en tus archivos de configuracioacuten y el HTML cambiaraacute el servidor automaacuteticamente y definirpoacutelizas de expiracioacuten para tu contenidoFormHelper Contiene funciones para crear formas basadas en modelos de Rails incluyendo inputselecciones botones radiales aacutereas de teacutexto etceacuteteraJavaScriptHelper Contiene funciones que te permiten trabajar con Javascript maacutes faacutecilmente enparticular con prototype que estaacute incluido en RailsUrlHelper te permite hacer enlaces urls de mailto etceacutetera mencionando controladores directamente sintener que especificar los URLs

  • Tutorial de Ruby on Rails13
  • Contenido13
  • 1 Introduccioacuten13
  • 2 Instalando Rails13
  • 3 Nuestra primera aplicacioacuten13
  • 4 Teoriacutea El Paradigma MVC13
  • 5 Teoriacutea Pruebas de Unidad13
  • 6 Configurando la Base de Datos13
  • 7 Creando un Moacutedulo con Modelo Controlador y Vista13
  • 8 Control de Versiones con Subversion13
  • 9 Pruebas de Unidad13
  • 10 Teoriacutea de Objetos13
  • 11 Mapeo de Objetos a Relaciones
  • 12 Modificando el Moacutedulo Generado13
  • 13 Buen Disentildeo con CSS13
  • 14 Utilizando Helpers13