En marcha con Rails (y II)

Tomado de: http://sobrerailes.com/pages/en_marcha_con_rails_2

Bienvenidos de nuevo.

En la primera parte del tutorial apenas empezamos a vislumbrar todas las cosas que pueden hacerse con Ruby on Rails. Por ejemplo, no hablamos sobre la validación de datos, las transacciones en la base de datos, las callbacks, el subsistema de pruebas unitarias o la caché. No hicimos mención alguna de los helpers que ofrece Rails para hacernos la vida más fácil. Aunque en realidad es imposible hacer justicia a ninguno de estos temas en el espacio limitado de este artículo sí que trataremos con cierto detalle alguno de ellos y del resto presentaremos un breve resumen, con enlaces a páginas con información más detallada.

Tampoco entramos con profundidad en el lenguaje de programación Ruby (a propósito). Si te interesa leer un breve tratado sobre los porqués que hay detrás de Ruby y del código Rails que vimos en la primera parte, te recomiendo que visites el blog de Amy Hoy, concretamente la historia Really Getting Started in Rails.

Pero antes de pasar a cubrir todo este material, quiero completar los ejercicios de tareas que dejamos pendientes al final de la primera parte:

  • Ya no hay forma de eliminar una receta. Añádele un botón -o enlace- de borrado a la plantilla de edición.
  • En la página principal de las recetas no hay ningún enlace a las páginas que permiten editar categorías. Arréglalo.
  • Estaría bien poder visualizar de alguna forma sólo las recetas que pertenecen a una categoría particular. Por ejemplo, tal vez me gustaría ver una lista de todas los snacks o una lista de todas las bebidas. En la página que lista las recetas, haz que el nombre de la categoría sea un enlace a una página que visualice todas las recetas de esa categoría.

Un astuto lector nos ha señalado que después de añadir categorías a nuestra aplicación ya no era posible crear nuevas recetas porque la acción new del controlador Receta, tal y como la proporciona el andamiaje no tiene manera de asignar una categoría, y esto hace que la acción list en la lista de recetas provoque un error. Por supuesto esto hay que arreglarlo.

¿Estás listo? ¡Empezamos!

Actualización de Ruby on Rails

[N. del T: aunque las versiones de Rails y de los componentes que has instalado si has seguido los pasos de este artículo son superiores a las que describe Curt y por tanto no es necesario actualizarse (o al menos no tan perentorio), el procedimiento que él describe para actualizar nuestro paquete Rails sí que sigue siendo válido, asi que también lo incluiré en la versión traducida.]

Cuando escribí la primera parte, la última versión de Rails era la 0.9.3, mientras que en el momento de escribir esta segunda parte, Rails ya va por la versión 0.10.0 y tiene algunas caracerísticas nuevas. Utilizaremos Rails 0.10.0 en este artículo, así que describiremos la actualización. Ten en cuenta que si te instalaste Rails después del 24 de Febrero de 2005 ya tienes la 0.10.0 instalada.

La figura 1 muestra cómo ver qué Gems de Ruby tenemos instaladas, así como sus números de versión. Como en la primera parte, estoy trabajando en un sistema Windows, así que tendrás que traducir un poco todo esto si usas una plataforma diferente.

Listado de Gems instaladas
Figura 1. Listado de Gems instaladas

Abre una ventana de terminal y ejecuta lo siguiente:

gem list --local

Truco: el comando gem list --remote mostrará todas las gems disponibles en el servidor de rubyforge.org.

Si no tienes instalado Rails 0.10.0 (o posterior), para actualizar a la última versión sólo hace falta volver a ejecutar el comando:

gem install rails

Actualización de seguridad de MySQL

En la primera parte, te recomendé que dejases la clave de administrador de MySQL vacía porque (en el momento de escribir el artículo) Rails aún no soportaba el nuevo protocolo de claves. Muchos de vosotros no estabais conformes con esta situación y, para empeorarlo todo, ahora existe un virus que explota vulnerabilidades de clave en MySQL sobre Windows. Afortunadamente, a partir de la versión 0.9.4, Rails soporta el nuevo protocolo de claves.

Nueva funcionalidad del scaffold

Rails ha incoporado una nueva funcionalidad en el andamiaje, que no exploraremos aquí en profundidad pero que es tan interesante que no quiero dejar pasar la oportunidad de contarla. Es mejor ilustrarla con un ejemplo.

En la primera parte se vio como crear un modelo y un controlador para la clase Receta con los siguientes comandos:

ruby scriptgenerate model Receta
ruby scriptgenerate controller Receta

Y luego instanciamos el andamiaje insertando scaffold :receta en la clase RecetaController. Todo lo generado por este sistema, es decir, el controlador con métodos CRUD (creación, acceso, actualización y borrado) así como las plantillas resultantes, eran creados al vuelo en tiempo de ejecución y no era posible inspeccionarlos.

Esta técnica sigue funcionando, pero ahora tenemos otra opción. Podemos ejecutar el siguiente comando,

ruby scriptgenerate scaffold Receta

que generará tanto el modelo como el controlador y además crea el código y vistas del andamiaje para todas las operaciones CRUD, lo cual nos permite ver este código generado y modificarlo para adaptarlo a nuestras necesidades. Conviene tener cuidado porque si ya se han creado modelos, controladores o plantillas sobreescribirá cualquier fichero existente al ir generando los contenidos.

Acabar la aplicación Recetario

Ha llegado la hora de pulir un poco la aplicación de la lista de recetas. Después presentaré otras prestaciones de rails que estoy seguro que resultarán interesantes.

Recuerda: en la primera parte, creamos la aplicación del recetario en el directorio c:\rails\recetario; y todas las rutas de directorio que se usan en este artículo asumirán este directorio base. Si escoges un lugar distinto asegúrate de hacer los cambios apropiados en los ejemplos de este artículo.

También te puedes descargar el codigo fuente de la versión en inglés de este tutorial en un único archivo zip. Funcionará bajo Rails 0.13 y posteriores, así que si aún utilizas una versión anterior de Rails, te sugiero que sigas las insrucciones de actualización descritas anteriormente.

Ah, y para todos los que estáis haciendo trampas (ellos saben quiénes son) y teneis pensado descargar el código fuente sin pasar primero por la primera parte, también os hará falta crearos una base de datos llamada recetario en MySQL y rellenarla.

Creación de una nueva receta con categorías

Dado que el código sigue usando el andamiaje para crear nuevas recetas, no hay manera de asignar una categoría a una receta. Esto no sería tan grave salvo por el detalle de que la página que hemos creado para mostrar todas las recetas asume que cada receta tendrá asignada una categoría y Rails generará un error si esto no se cumple. Esto significa que, en el estado que dejamos las cosas en la primera parte, tras añadir una nueva receta tendremos un error al intentar ver la lista de recetas.

El arreglo consiste en capturar la acción new del andamiaje como hicimos con la acción edit. Abre c:\rails\recetario\app\controllers\receta_controller.rb y añade el método new como en la figura 2.

El nuevo código del método new del controlador Receta
Figura 2. El nuevo código del método new del controlador Receta.

La sentencia @receta = Receta.new crea un nuevo objeto receta vacío y se lo asigna a la variable de instacia @receta. Recuerda que una instancia de la clase Receta representa una fila en la tabla recetas de nuestra base de datos. Así pues cuando creamos una nueva instancia, la clase Receta puede asignar valores por defecto para que los utilice la plantilla de la vista.

Ahora mismo la clase del modelo Receta no pone ningún valor por defecto, pero la plantilla que voy a mostrar usará cualquier cosa que esté en el objeto @receta para inicializar el formulario del display. Más adelante, puedes añadir los valores por defecto en la clase Receta que se mostrarán cuando crees una nueva receta.

Como con la acción edit, este código también recupera una colección de todas las categorías de forma que pueda visualizar una lista desplegable con las categorías de entre las cuales el usuario puede escoger. La variable de instancia @categorias es la que lleva esta lista.

En el directorio c:\rails\recetario\app\views\receta, crea un fichero denominado new.rhtml que contenga la plantilla que se muestra debajo. Como es habitual, se trata en su mayor parte de HTML con algo de código para mostrar las etiquetas select y option para el desplegable con la lista de categorías:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 
 <head>
 <title>Nueva Receta</title>
 </head>
  
 <body>
 <h1>Nueva Receta</h1>
 
 <form action="/receta/create" method="post">
 
   <p>
   <b>Titulo</b><br/>
   <input id="receta_titulo" name="receta[titulo]" size="30" type="text" value=""/>
   </p>
   
   <p>
   <b>Descripcion</b><br/>
   <input id="receta_descripcion" name="receta[descripcion]" size="30" type="text" value=""/>
   </p>
   
   <p>
   <b>Categoria:</b><br/>
   <select name="receta[categoria_id]">
 
   <% @categorias.each do |categoria| %>
        <option value="<%= categoria.id %>"> 
        <%= categoria.nombre %>
        </option>
   <% end %>
   
   </select>
   
   </p>
   <p>
 
   <b>Instrucciones</b><br/>
   <textarea cols="40" id="receta_instrucciones" name="receta[instrucciones]" 
      rows="20" wrap="virtual">
   </textarea>
   </p>
   
   <input type="submit" value="Create"/>
 </form>
  
 <a href="/receta/list">Back</a> 
 </body>
</html>

Como puede verse no hay mucha diferencia con respecto a la plantilla del método edit que ya vimos en la primera parte. Hemos omitido la fecha de la receta porque la ajustaremos por código cuando el usuario envíe el formulario a la aplicación, para estar seguros de que la fecha de la receta siempre será su fecha exacta de creación.

Si observas la etiqueta del formulario verás que se envía a la acción create del controlador receta. Edita c:\rails\recetario\app\controllers\receta_controller.rb y añade el método create, que recibirá los datos introducidos en el formulario anterior:

1
2
3
4
5
6
7
8
9 
def create
    @receta = Receta.new(@params['receta'])
    @receta.fecha = Date.today
    if @receta.save
        redirect_to :action => 'list'
    else
        render_action 'new'
    end
end

Este método en primer lugar crea un nuevo objeto para la receta y lo inicializa con los parámetros introducidos en new.rhtml. Luego le ajusta la fecha a la receta con la fecha de hoy y le indica al objeto receta que se guarde en la base de datos. Si la operación tiene éxito, nos redirige a la acción listado que muestra todas las recetas, mientras que si no hemos podido grabar los datos en la base de datos, volveremos a la acción new de forma que el usuario lo pueda volver a intentar.

Vamos a probarlo. Arranca el servidor web abriendo una ventana de terminal, cambiando al directorio c:\rails\recetario y ejecutando el comando ruby script\server. Luego abre con el navegador http://127.0.0.1:3000/receta/new y añade una nueva receta como en la figura 3.

Nueva receta con categor�a
Figura 3. Nueva receta con categoria

Tras crear la nueva receta debería verse algo parecido a la figura 4.

listado con todas las recetas
Figura 4. Listado con todas las recetas

Borrado de recetas

Si recuerdas la primera parte del artículo, una vez que escribimos nuestra propia acción para el listado de recetas (sustituyendo la del scaffold) dejamos de poder borrar una receta. Para implementar esto en la acción del listado, añadiré un enlace para el borrado después del nombre de cada receta en la página principal, de forma que al seguir ese enlace se borre su receta asociada. Esto es fácil.

Primero, edita c:\rails\recetario\app\views\receta\list.rhtml y añadele el enlace al borrado de la siguiente manera:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 
 <head>
   <title>Todas las Recetas</title>
 </head>
 <body> 
   <h1>Recetario Online - Todas las Recetas</h1>
   <table border="1">
    <tr>
      <td width="40%"><p align="center"><i><b>Receta</b></i></td>
      <td width="20%"><p align="center"><i><b>Categoria</b></i></td>
      <td width="20%"><p align="center"><i><b>Fecha</b></i></td>
    </tr>
    <% @recetas.each do |receta| %>
      <tr>
        <td>
        <%= link_to receta.titulo, 
                    :action => "show", 
                    :id => receta.id %>
        <font size=-1>
           
        <%= link_to "(delete)", 
                    {:action => "delete", :id => receta.id},
                    :confirm => "¿Seguro que quieres borrar #{receta.titulo}?" %>
        </font>
        </td>
        <td><%= receta.categoria.nombre %></td>
        <td><%= receta.fecha %></td>
      </tr>
    <% end %>
   </table>
 <p><%= link_to "Nueva receta", :action => "new" %></p> 
 </body>

El cambio principal es que hemos añadido este enlace:

1
2 
<%= link_to "(delete)", {:action => "delete", :id => receta.id},
           :confirm => "¿Seguro que quieres borrar #{receta.titulo}?" %>

Este enlace es un poco distinto a los que hemos venido añadiendo hasta ahora, porque emplea una opción que genera automáticamente un diálogo de confirmación Javascript. Si el usuario pulsa en OK en este diálogo se seguirá el enlace, y si pulsa en Cancelar no se ejecutará ninguna acción.

Probémoslo visitando esta URL

http://127.0.0.1:3000/receta/list

Intenta borrar la receta llamada «Agua helada», pero pulsa Cancelar cuando aparezca el diálogo. Deberías ver algo parecido a la figura 5.Diálogo de confirmación al borrar  una receta
Figura 5. Diálogo de confirmación al borrar una receta

Vuelve a intentarlo, pero esta vez confirma el diálogo. ¿Ha aparecido lo que muestra la figura 6?

Error al borrar la receta del agua helada
Figura 6. Error al borrar la receta del agua helada

Está bien, lo admito: lo he hecho a propósito para recordar que no pasa nada si se cometen errores. He añadido un enlace a la acción delete en la plantilla de la vista, pero ¡no hemos creado dicha acción en el controlador!

Edita c:\rails\recetario\app\controllers\receta_controller.rb y añade el siguiente método delete:

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

La primera línea encuentra la receta con el ID recibido en el enlace, y luego invoca el método destroy de la receta. La segunda línea nos redirige a la acción de listado.

Vamos a intentarlo otra vez. Abre http://127.0.0.1:3000/receta/list e intenta borrar la receta de Agua helada. Esta vez debería aparecer la figura 7, sin la receta de Agua Helada.

Hemos borrado la receta de agua helada
Figure 7. Hemos borrado la receta de agua helada

Utilizando los layouts

En la primera parte utilizamos el andamiaje para proporcionar todas las operaciones CRUD para las categorias, pero no creé ningún enlace desde nuestra página principal del listado de recetas. En vez de colocar un enlace en la página del listado de recetas, quiero hacer algo que por lo general me será más util: crear un número de enlaces que aparecerán debajo de todas mis páginas. Rails tiene una característica, los layouts, que han sido especialmente concebidos para esta tareas.

Casi todos los sitios web muestran cabeceras y pies de página comunes. Esto se consigue haciendo que cada página «incluya» un texto especial para la cabecera y el pie de página. Los layouts de Rails le dan la vuelta a este patrón haciendo que el fichero del layout «incluya» el contenido de la página. Es más fácil verlo que describirlo.

Edita c:\rails\recetario\app\controllers\receta_controller.rb y añade la linea layout inmediatamente después de la definición de la clase, como se muestra en la figura 8.

añadiendo un layout al controlador  de Receta
Figura 8. Añadiendo un layout al controlador de Receta

Con esto le decimos al controlador de las recetas que utilice el archivo standard-layout.rhtml para la maquetación de todas las páginas que tenga que pintar, y Rails lo buscará en c:\rails\recetario\app\views\layouts\standard-layout.rhtml. Crea el archivo con el siguiente contenido:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 
 <head>
   <title>Recetario Online</title>
 </head>
 <body>
   <h1>Recetario Online</h1>
   <%= @content_for_layout %>
   <p>
     <%= link_to "Crear nueva receta", 
                 :controller => "receta", 
                 :action => "new" %>
     
   <%= link_to "Ver todas las recetas", 
               :controller => "receta", 
               :action => "list" %>
     
   <%= link_to "Ver todas las categorías", 
               :controller => "categoria", 
               :action => "list" %>
   </p>
 </body>

Sólo hay una diferencia con respecto a las otras plantillas que hemos creado hasta ahora, se trata de la siguiente línea:

<%= @content_for_layout %>

Aquí es donde se insertará el contenido pintado por cada acción del controlador en la plantilla del layout. Observa también que he usado enlaces que especifican tanto el controlador como la acción (hasta ahora, por defecto iban al mismo controlador que se estaba ejecutando) Aunque esto es obligatorio en el caso del enlace al listado de categorías, en el caso de los otros dos se podría haber usado la forma abreviada (sólo la acción).

Pero antes de probarlo, hace falta hacer una cosa más. Las plantillas anteriores para las recetas tenían algunas etiquetas HTML que ahora aparecen en el layout, por lo tanto editaremos c:\rails\recetario\app\views\receta\list.rhtml y borraremos las lineas del princpio y del final para que quede así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 
 <tr>
   <td width="40%"><p align="center"><i><b>Receta</b></i></td>
   <td width="20%"><p align="center"><i><b>Categoria</b></i></td>
   <td width="20%"><p align="center"><i><b>Fecha</b></i></td>
 </tr>
 <% @recetas.each do |receta| %>
   <tr>
     <td>
     <%= link_to receta.titulo, 
                 :action => "show", 
                 :id => receta.id %>
     <font size=-1>
        
     <%= link_to "(borrar)", 
                 {:action => "delete", :id => recipe.id},
                 :confirm => "¿Seguro que quieres borrar #{recipe.titulo}?" %>
     </font>
     </td>
     <td><%= receta.categoria.nombre %></td>
     <td><%= receta.fecha %></td>
   </tr>
 <% end %>

Igualmente, edita c:\rails\recetario\app\views\receta\edit.rhtml y c:\rails\recetario\app\views\receta\new.rhtml para quitar las mismas líneas. Recuerda que sólo deben quedar las etiquetas del formulario y lo que queda entre ellas.

Abre http://127.0.0.1:3000/receta/list, y deberías ver algo parecido a la figura 9.

using a layout with common links
Figura 9. Utilizando un layout con enlaces comunes

Los tres enlaces que aparecen abajo, al final de la página, deberían salir en todas las páginas generadas por el controlador de las recetas. ¡Compruébalo!

Si pulsas en el enlace de «Ver todas las categorías», te darás cuenta de que los nuevos enlaces no salen. Esto se debe a que el listado de categorías es generado por el controlador de las categorías, y el único controlador que sabe usar el nuevo layout es el de las recetas.

Para corregirlo, edita c:\rails\recetario\app\controllers\categoria_controller.rb y añade, igual que antes, la linea de layout como en la figura 10.

añadiendo el layout al controlador de las categorias
Figura 10. Añadiendo el layout al controlador de las categorías

Ahora deberían verse los enlaces comunes en la parte inferior de todas las páginas mostradas por la aplicación del recetario.

Mostrar las recetas de una categoría específica

La última tarea que nos queda es añadir la posibilidad de mostrar en nuestro listado sólo las recetas que pertenezcan a una categoría en particular. Cogeremos la categoría visualizada con cada receta en la página principal y la convertiremos en un enlace que mostrará sólo las recetas de esa categoría.

Para hacerlo, cambiaremos la plantilla de la lista de recetas para aceptar un parámetro en la URL que especificará por qué categoría realizar el filtrado, o bien ver todas las categorías si el usuario ha omitido el parámetro. Por tanto, en primer lugar tengo que cambiar el método de la acción list para usar este parámetro y pasárselo a la plantilla de la vista.

Edita c:\rails\recetario\app\controllers\receta_controller.rb y modifica el método list así:

def list
    @categoria = @params['categoria']
    @recetas = Receta.find_all
end

Y luego edita c:\rails\recetario\app\views\receta\list.rhtml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 
 <tr>
   <td width="40%"><p align="center"><i><b>Receta</b></i></td>
   <td width="20%"><p align="center"><i><b>Categoria</b></i></td>
   <td width="20%"><p align="center"><i><b>Fecha</b></i></td>
 </tr>

 <% @recetas.each do |receta| %>
   <% if (@categoria == nil) || (@categoria == receta.categoria.nombre)%>
     <tr>
      <td>
        <%= link_to receta.titulo, 
                   :action => "show", 
                   :id => receta.id %>
        <font size=-1>
           
        <%= link_to "(borrar)", 
                    {:action => "delete", :id => receta.id},
                    :confirm => "¿Seguro que quieres borrar #{receta.titulo}?" %>
        </font>
      </td>
      <td>
        <%= link_to receta.categoria.nombre, 
                    :action => "list", 
                    :categoria => "#{receta.categoria.nombre}" %>
      </td>
      <td><%= receta.fecha %></td>
     </tr>
   <% end %>
 <% end %>

Hay dos cambios fundamentales. Primero, la línea:

<% if (@categoria == nil) || (@categoria == receta.categoria.nombre)%>

decide si tenemos que mostrar la receta que se está tratando en el bucle. Si la categoría es nil (es decir, no había parámetro de categoría en la URL), o si la categoría del parámetro recibido en la URL coincide con la categoría de la receta actual, se muestra.

En segundo lugar, esta línea:

1
2
3 
<%= link_to receta.categoria.nombre, 
    :action => "list", 
    :categoria => "#{receta.categoria.nombre}" %>

crea un enlace a la acción de listado que incluya el parámetro de categoría apropiado.

Abre http://127.0.0.1:3000/receta/list y pulsa en uno de los enlaces de snacks. Debería tener el aspecto de la Figura 11.

showing only snacks
Figure 11. Listado sólo de snacks

¿Ya? ¿Cuánto hemos tardado?

¡Ya está! Tenemos una aplicación online razonablemente funcional desarrollada en un tiempo record. Por supuesto, es un esqueleto que está pidiendo a gritos un mejor acabado.

Entre tantas palabras y pantallas puede que se haya difuminado (al menos un poco) qué es lo que este código puede hacer y en qué cantidad de tiempo de desarrollo. Con vuestro permiso, voy a presentaros algunas estadísticas para ponerlo todo en perspectiva.

Por suerte, Rails tiene ciertas facilidades que nos ayudan a respondernos estas preguntas. Abre una ventana de terminal en el directorio de la aplicación (c:\rails\recetario) y ejecuta el comando:

rake stats

Deberían salir unos resultados parecidos a los de la figura 12 (LOC significa «líneas de código»)

viewing development statistics
Figura 12. Estadísticas de desarrollo

No veremos una descripción detallada de cada cifra que aparece en el listado, sin embargo la última línea tiene lo que quiero destacar:

Code LOC: 47

Esto significa que el número real de líneas de código de esta aplicación (sin contar comentarios o el código de pruebas) es 47. ¡He tardado una media hora en crear la aplicación! No es posible alcanzar este grado de productividad en ningún otro entorno de desarrollo de aplicaciones web que yo conozca.

A lo mejor piensas que esta es una experiencia aislada que usa un ejemplo simple (trivial si se quiere), o quizá piensas que esto puede servir para proyectitos pequeños, pero que no puede escalarse a soluciones más grandes. Si albergas estas dudas, la próxima sección puede ayudar a aclararlas.

Historias de éxito con Ruby on Rails

Rails es un framework relativamente joven: en el momento de escribir este artículo tan sólo han pasado unos seis meses desde la primera versión pública. Sin embargo, Rails ha debutado con tanta estabilidad y características que rápidamente ha surgido una prometedora comunidad a su alrededor. En este lapso de tiempo han aparecido varias aplicaciones web desarrolladas usando Ruby on Rails.

Basecamp

De la web del propio sitio:

Basecamp es una herramienta basada en web que te permite gestionar proyectos (o simplemente ideas ) y crear de forma rápida extranets para clientes o proyectos. Te permite a tí y a tus clientes (o a tu eqipo de desarrollo) mantener las conversaciones, ideas, planificaciones, listas de tareas y más en una localización central protegida por claves.

Basecamp fue la primera web comercial que funcionaba con Ruby on Rails, y fue desarrollada por David Heinemeier Hansson, el creador de Rails. En el momento de su inauguración, contenía 4000 líneas de código con dos meses de desarrollo por un único programador. A finales de 2004, Basecamp declaró que había superado la marca de 10000 usuarios registrados. El número de usuarios real se considera información privada, pero la página principal afirma que los usuarios se cuentan por «decenas de miles».

43 Things

43 Things es una aplicación social para fijar objetivos. En la actualidad tiene 6000 usuarios registrados y cientos de miles de visitas anónimas. 43 Things consiste en 4500 líneas de código escritas en tres meses por tres desarrolladores trabajando a tiempo completo.

Ta-da Lists

Ta-da Lists es un servicio gratuito que permite gestionar listas compartidas de tareas pendientes. Su interfaz de usuario es muy ágil, y utiliza XMLHttpRequest para minimizar las esperas al servidor. Esta aplicación la hizo un desarrollador en una semana, produciendo 579 líneas de código.

Snow Devil

Snow Devil es una tienda online especializada en snowboards y equipamiento relacionado. Ha sido recientemente inaugurada, por lo que no disponemos de información de uso en este momento. Sin embargo, sí que sabemos que la aplicación tiene 6000 líneas de código escritas por dos desarrolladores en cuatro meses.

Rediseño de CD Baby

CD Baby es una popular tienda de música independiente. Abierta en 1998, tiene en catálogo 82443 artistas que han vendido entre todos 1.2 millones de CDs, generandoles unos ingresos de 12 millones de dólares a dichos artistas.

La anterior página web de CD Baby consistía en 90000 líneas de código PHP que cada vez se hacían más difíciles de manejar. Sus autores están en proceso de reescribirlo todo con Ruby on Rails. Aún es pronto para encontrar información acerca del desarrollo pero el propietario de CD baby publica en un blog el proceso y el avance de la conversión.

¿Qué quiere decir todo esto?

En última instancia, tener un buen diseño siempre influye más que el framework en el rendimiento de tu aplicación: hay que pensar detenidamente el diseño de la base de datos y los índices de las tablas, analizar los patrones de acceso y plantearse desnormalizar los datos, buscar oportunidades para cachear datos preprocesados…

Rails tiene características muy potentes que hacen fácil prototipar y desarrollar tu aplicación más deprisa, lo cual te dejará más tiempo para pensar acerca de las prestaciones de tu aplicación y cómo afinar su rendimiento.

Un repaso breve a las características de Ruby on Rails

Hay muchas funcionalidades de Rails de las que no hemos hablado en este artículo. Me gustaría mencionar algunas de ellas (con enlaces a información adicional) para terminar de redondear la impresión general de las herramientas que ofrece Rails.

Caché

Mantener una caché es una forma barata de acelerar la aplicación guardando los resultados de procesamientos previos (cálculos, llamadas a la base de datos, visualizaciones de página, etc.) de forma que para la siguiente vez se omita el procesamiento. Rails proporciona tres niveles de caché, con diversos grados de granularidad:

  • caché de páginas
  • caché de acciones
  • caché de fragmentos

Validación y callbacks

Debes validar los datos para estar seguro de que son correctos y completos antes de escribirlos en la base de datos. Rails dispone de un mecanismo simple que permite a tu aplicación validar un objeto de datos antes de que el propio objeto actualice o cree los campos correspondientes en la base de datos. Léete el Validation How-to o ve directamente a la documentación del API sobre validación.

Las callbacks de ActiveRecord se «enganchan» a un objeto de datos y pueden activar cierto código que se ejecutará antes o después de que una operación altere el estado del objeto.

Transacciones

ActiveRecord también soporta transacciones. Citando directamente la documentación:

Las transacciones son bloques protegidos donde las sentencias SQL sólo son permanentes si todas tienen éxito como una única acción atómica. El ejemplo clásico es el de una transferencia entre dos cuentas donde sólo se puede hacer un depósito en la cuenta destino si la cuenta de origen dispone de fondos. Las transacciones fuerzan la integridad de la base de datos y protegen los datos de errores en el código del programa o caídas de la base de datos. Así, deberías usar bloques de transacción siempre que tengas un número de sentencias que deben ser ejecutadas todas o ninguna de ellas.

Por ejemplo, considérese el código:

transaction do
    david.reintegro(100)
    mary.deposito(100)
end

Pruebas

Rails ha sido desarrollado teniendo en cuenta las pruebas y permite probar tu aplicación web de manera exhaustiva. Hay todo un extenso tutorial online que muestra cómo podemos probar una aplicación Rails.

Generadores

Los generadores son los scripts de ayudas que se usan para generar código. Ya hemos usado algunos generadores para crear nuevos controladores y modelos, y al principio de este artículo he mostrado cómo se puede usar un nuevo generador para crear el código de andamiaje.

Rails también soporta generadores creados por el usuario. Por ejemplo, Tobias Luetke ha escrito un Generador de Login que crea todo el código necesario para añadirle a tu aplicación Rails la funcionalidad de registro de usuarios, altas, etc.

Seguridad

A estas alturas todos deberíamos reconocer la importancia de la seguridad en las aplicaciones web. El sitio web de Ruby on Rails tiene un manual sobre seguridad que describe los problemas comunes de seguridad en las aplicaciones web y cómo evitarlos con Rails.

Conclusiones

Rails no es una prueba de concepto ni un framework corriente. Es la siguiente generación de entornos de desarrollo web y los desarrolladores que lo usen crearán sus aplicaciones más deprisa que los que no lo hagan; incluso desarrolladores que trabajen solos pueden ser tan productivos como equipos completos. Y lo mejor de todo: está disponible ya, bajo licencia MIT.

Creo que no ha habido en toda la historia reciente de la programación una mejora comparable en cuanto a productividad.

Un comentario sobre "En marcha con Rails (y II)"

Deja un comentario