Creando una aplicación web con Ruby on Rails: Capítulo 1

22 de Marzo de 2009 • 14 comentarios

Se suele comentar que Rails y Ajax se llevan bien. Vamos a demostrarlo creando una pequeña aplicación pseudo GTD para mantener una lista de TODO’s. Aunque en el primer capítulo aún no se verá Ajax, aparecerá muy pronto. Fácilmente se puede extender para gestionar varias listas, pero interesa mantener el código simple.

Comprovamos las versiones de Ruby y Rails, y creamos la aplicación con el comando rails. El comando mate . abre el editor TextMate (sólo para Mac OS X). Aquí usad el equivalente para vuestro editor o simplemente abrid el directorio con vuestro navegador de ficheros.

~% ruby -v
ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]
~% rails -v
Rails 2.3.2
~% rails microtodo
      create
      create  app/controllers
      [...]
      create  log/test.log
~% cd microtodo
~/microtodo% mate .

Ahora toca respirar un poco y curiosear por el directorio que acabamos de crear y llenar. Podríamos ejecutar script/server y abrir con nuestro navegador http://0.0.0.0:3000/ para ver la página inicial de Rails, pero si habéis seguido la entrada anterior, esto no es necesario.

A continuación nos cargaremos esta página inicial (el objetivo es ver la lista de tareas por hacer cuando vayamos a la página principal) y usaremos el generador scaffold para las tareas. Crearemos el modelo TodoItem y la migración a la base de datos con tres campos: task: string (descripción de la tarea), position: integer (para poder reorganizar las tareas como nos parezca) y completed_at: timestamp (para saber si una tarea se ha completado y en qué instante se ha hecho). Una migración es un pequeño código ruby que se convertirá en sentencias SQL al ejecutar el comando rake db:migrate. Recomiendo echar un vistazo a la guía sobre migrations. El generador scaffold además crea el controlador TodoItemsController, las vistas para las acciones CRUD, un layout para el controlador y un fichero css básico.

~/microtodo% rm public/index.html
~/microtodo% script/generate scaffold TodoItem task:string position:integer completed_at:timestamp
      [...]
~/microtodo% rake db:migrate
(in /Users/jordi/microtodo)
==  CreateTodoItems: migrating ================================================
-- create_table(:todo_items)
   -> 0.0037s
==  CreateTodoItems: migrated (0.0041s) =======================================
 
~/microtodo%

Ahora es un buen momento para ejecutar script/server y jugar un poco con las tareas generadas por el scaffold. A continuación vamos a hacer que el controlador TodoItemsController responda a la página inicial modificando el fichero config/routes.rb y dejándolo así:

1
2
3
4
5
6
ActionController::Routing::Routes.draw do |map|
 
  map.resources :todo_items
  map.root :todo_items
 
end

Hoy acabaremos el capítulo uno limpiando un poco los views modificando los ficheros de app/views/todo_items. Primero borraremos el fichero show.html.erb puesto que no nos interesa una página para cada To Do Item, luego editaremos index.html.erb, edit.html.erb y new.html.erb y crearemos _form.html.erb con este contenido:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- index.html.erb -->
<h1>Things To Do</h1>
 
<% @todo_items.each do |todo_item| %>
  <% div_for todo_item do %>
    <%= h todo_item.task %>
    (<%= link_to 'Edit', edit_todo_item_path(todo_item) %>)
    <small>(<%= link_to 'Destroy', todo_item, :confirm => 'Are you sure?', :method => :delete %>)</small>
  <% end %>
<% end %>
 
<br />
 
<%= link_to 'Add To Do Item', new_todo_item_path %>

Aquí observamos el uso del iterador each sobre la variable @todo_items que se crea en el controlador. Se usa el clásico bloque de Ruby, y para cada todo_item usamos los helpers que Rails nos ofrece para definir un <div> que contiene la descripción de la tarea y enlaces para editarla y eliminarla. Sustituiremos estos enlaces por edición y eliminación in-situ usando Ajax, pero será en otro capítulo.

Vamos las vistas de las acciones edit y new, que son muy parecidas:

1
2
3
4
5
6
<!-- edit.html.erb -->
<h1>Editing To Do Item</h1>
 
<%= render :partial => "form", :locals => { :todo_item => @todo_item, :button_label => "Update Item" } %>
 
<%= link_to 'Back', todo_items_path %>
1
2
3
4
5
6
<!-- new.html.erb -->
<h1>New To Do Item</h1>
 
<%= render :partial => "form", :locals => { :todo_item => @todo_item, :button_label => "Add Item" } %>
 
<%= link_to 'Back', todo_items_path %>

Aquí, además de usar el helper link_to que ya hemos visto en la anterior vista, utilizamos render :partial, que es una herramienta muy potente que permite mantener el código mas limpio siguiendo fielmente el principio DRY. Más información en la guía Layout and Rendering.

Finalmente, la nueva vista que se usará en las acciones edit y new para mostrar el formulario. Tener este formulario duplicado era muy poco DRY, y puesto que usamos los helpers de Rails para crear los campos del formulario, si el objeto todo_item contiene información se mostrará en el campo creado por el helper.

1
2
3
4
5
6
7
8
9
10
11
<!-- _form.html.erb -->
<% form_for(todo_item) do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label :task %><br />
    <%= f.text_field :task %>
  </p>
  <p>
    <%= f.submit button_label %>
  </p>
<% end %>

Casi estamos por hoy, pero si nos cargamos la vista para la acción show, tenemos que modificar el controlador para que nunca intente llevarnos a ver un To Do Item. Concretamente, el controlador creado por el scaffolding hace un redirect a la página /todo_items/ID después de crear o editar una tarea. Cambiaremos este comportamiento modificando las acciones create y update.

Modificamos las líneas 48 y 65 del fichero app/controllers/todo_items_controller.rb:

48
        format.html { redirect_to(@todo_item) }
65
        format.html { redirect_to(@todo_item) }

por

48
        format.html { redirect_to(todo_items_url) }
65
        format.html { redirect_to(todo_items_url) }

Hasta aquí en este primer capítulo. En el próximo haremos que toda la acción suceda en una página, insertando tareas desde la página principal y haciendo que una tarea se pueda completar con un checkbox, ambas acciones usando Ajax.

He colgado el proyecto en Github, por si en lugar de seguir los pasos queréis consultar directamente el resultado. Si no usáis Git, os podéis bajar un tarball también desde Github.

Responderé encantado cualquier duda que aparezca siguiendo este tutorial.

22 de Marzo de 2009 • 14 comentarios
  1. Stalyn dice:

    Gracias :) muy interesante.

  2. Mutsuda dice:

    Molt interessant, aprendré RoR a base dels teus tutorials xD!

  3. Stalyn dice:

    Que editor recomiendas para wondox? Y que erramientas son necesarias para empesar con el rail? Tambien es preferido apreder solo ruby andtes de empesar con RoR?

    Gracias.

  4. Jordi Romero dice:

    @Stalyn: Uno de los motivos por los que cambié a Mac OS X era la poca comodidad que me ofrecía Windows como entorno de desarrollo. Aún así intentaré contestar: Yo soy un poco escéptico con los IDE’s tradicionales y muy completos, así que te recomendaría usar un editor de texto sencillo (Como el e TextEditor o el propio SciTE que se te instalará con el Ruby Installer oficial. Si te gustan los IDE’s, sin duda el mejor es NetBeans for Ruby.

    Lo único que necesitas para empezar a programar Ruby on Rails (en Windows) es el instalador de Ruby y después como en cualquier plataforma: gem install rails. También tienes InstantRails, que en un solo EXE te lo deja todo preparado para empezar a programar (Contiene Ruby, Rails, Apache + Mysql). Tienes opciones para escoger, incluso puedes mirarte esta última guía sobre instalar rails en Windows.

    Y la última pregunta es muy interesante: El otro día empecé a escribir un post sobre el tema. Yo creo que es mejor empezar a programar en Ruby on Rails sin haber aprendido Ruby, y aprenderlo sobre la marcha. En este mismo tutorial puedes “entender” qué hace el código sin llegar a saber Ruby. Cuándo ya estás un poco iniciado en Rails, si aprendes Ruby en profundidad vas a comprender cómo funciona Ruby on Rails internamente y porqué es tan fantástico. Además, gracias a la flexibilidad de Ruby puedes escribir virguerías de código muy fácil de leer y eficaz, y aquí es donde Rails es imparable.

  5. Jordi Romero dice:

    Justo después de mandar el comentario estaba leyendo la guía del Wiki de Ruby on Rails sobre instalar Rails en Windows, y el enlace que hay en “Otros recursos” ha resultado muy interesante:

    The Best Environment for Rails on Windows (en inglés)

  6. Stalyn dice:

    Jordi, muchas gracias por tomarte tu tiempo para contestarme.

  7. afm dice:

    todo esto esta bien, pero alguien que me diga porfavor, como rayos conecto una base de datos mysql para trabajar con los datos que ya hay en el.
    Y otra cosa, al usar scaffold, la base de datos que se crea, en donde se esta almancenando, necesito correr el servidor de mysql?.

    todo mundo empieza con los comandos rake y migrate, pero quedan muchas cosas en el aire.

  8. Jordi Romero dice:

    Hola afm, Rails por defecto desde hace unas versiones usa SQLite, un sistema de bases de datos muy simple que usa un sólo fichero para almacenar la información (lo puedes encontrar en db/development.sqlite3). Es suficientemente rápido para entornos de desarrollo pero no para producción, donde se recomienda usar MySQL, etc…

    Si lo que quieres es cambiar a MySQL, tienes que modificar el fichero config/database.yml y escribir algo similar a esto:

    development:
    adapter: mysql
    encoding: utf8
    database: blog_development
    username: root
    password: password_mysql
    socket: /tmp/mysql.sock
    

    Despues, reinicia el servidor web y vuelve a hacer rake db:migrate. Con esto, has pasado de SQLite a MySQL. Si por otro lado quieres poder acceder a la base de datos SQLite que ya has creado e interactuar con ella, puedes ejecutar script/dbconsole. Espero que esto te oriente, para mas información consulta la guia Getting Started with Rails.

  9. el verdor dice:

    Muy bien explicado, y tengo una consulta, a ver si me la puedes resolver:

    ()

    por que uno llava el igual, otra una h y el otro script solo el <% ….

    gracias

  10. el verdor dice:

    Perdona, pero como he metido codigo, no aparece en el comentario, me refiero a las lineas 5,6 y 7 del fichero index.html.erb, un saludo

  11. Jordi Romero dice:

    Bueno, este es un fichero Erb: Un fichero con estructura HTML que contiene código Ruby integrado.

    Las etiquetas

    < % %>

    delimitan un trozo de código Ruby. Esto significa, que se ejecutará el código Ruby (se modificaran variables, llamaran funciones, etc…) pero no se devolverá (mostrará contenido HTML) nada.

    En cambio, las etiquetas

    < %= %>

    delimitan un trozo de código Ruby cuyo resultado se mostrará en el fichero.

    Entonces:

    <b>Contenido HTML normal</b>
    <% a = 3 %> <!-- Aquí no se muestra ningún valor en el fichero HTML, tan sólo se hacen cálculos -->
    <%= a %> <!-- Aquí se muestra un 3 en el fichero HTML -->
    <%= h(a) %> <!-- Aquí se muestra el valor de a (4) pero parseando su contenido para que no contenga contenido que pueda estropear el HTML -->

    Entonces, en el ejemplo que mencionas, la línea 4 itera sobre @todo_items, la línia 5 crea una etiqueta

    <div>

    (aquí no es necesario usar

    < %= %>

    porque la función div_for ya se encarga de imprimir), en la siguiente línea ponemos el contenido del campo task dentro de la variable todo_item, …

    4
    5
    6
    7
    8
    9
    10
    
    <% @todo_items.each do |todo_item| %>
      <% div_for todo_item do %>
        <%= h todo_item.task %>
        (<%= link_to 'Edit', edit_todo_item_path(todo_item) %>)
        <small>(<%= link_to 'Destroy', todo_item, :confirm => 'Are you sure?', :method => :delete %>)</small>
      <% end %>
    <% end %>

    Espero que haya sido suficiente la respuesta, para más información al respeto, mirate la guia de iniciación de la página de Ruby on Rails.

  12. el verdor dice:

    gracias, estoy un poco pez de ruby
    ahora que me acuerdo a los métodos con uno o menos argumentos no les hace falta ponerles paréntesis, es esto lo de la h ¿no?

  13. Jordi Romero dice:

    Exacto, h és un alias del método html_escape y el resto es el parámetro que se le pasa.

  14. fernando dice:

    hola, recien estoy empezando en RoR, y aun no se hacer casi nada, quiero saber como hacer para abrir un fichero ya creado, yo uso RoR en windows vista y ademas queria saber que editor puedo conseguir para windows, ya que hasta ahora solo uso la ventana DOS, muchas gracias.

Deja un comentario