Primeros pasos con REST en Rails
Esta vez haré una pequeña introducción a lo que es REST y cómo lo utilizamos en Rails, y más ahora que la versión 2.0 de Rails viene con un enfoque mayor (sino es que completamente) a las aplicaciones REST.
Pero primero, ¿qué es REST? REST significa (REpresentational State Transfer) y podríamos decir a groso modo que es un modelo de arquitectura de software, generalmente para aplicaciones hipermedia (web).
Desde el punto de vista de REST todo lo que existe en el servidor son recursos, podemos acceder y modificar estos recursos a través de un verbo aplicado a una URL. Es como si estuvieramos formando una oración, veamos:
En un blog los posts son un recurso, de hecho son dos. Uno es el conjunto de posts en sí (como el index del blog), y otro es un sólo post (cuando le damos en “Leer el artículo completo” y nos lleva a la página de ese único post).
La URL para el conjunto de posts sería algo como /articles, mientras que la del único post sería /articles/1
Ahora bien, los verbos que podemos aplicar a estas URLs son similares a los que aplicamos a una base de datos (CRUD: Create, Read, Update, Delete), y éstos son POST, GET, PUT, DELETE respectivamente.
Entonces si queremos por ejemplo:
- obtener la lista de posts
- GET /articles
- agregar un post al conjunto de posts
- POST /articles
- obtener un post
- GET /articles/1
- editar un post
- PUT /articles/1
Como ven en REST utilizamos una misma URL para diferentes acciones dependiendo del “verbo” (método) con que la llamemos, mientras que en la arquitectura común sería algo como /articles/new_article/ para agregar un post y /articles/show_article/1 para mostrarlo.
REST en Rails
REST simplifica las cosas, y por eso tenía que estar en Rails de una manera fácil.
Para ver cómo utilizar REST en Rails nos meteremos un poco a lo que son las rutas, aunque es un tema mas bien diferente REST implica manejo de URLs así que una pequeña repasada de routing no hará mal.
Cuando creamos una aplicación en Rails con el comando rails myapp, nos crea un fichero llamado config/routes.rb, este es el archivo mágico.
Si ejecutamos un generador resource article además de crearnos un modelo, controlador y vistas nos agregará una línea map.resources :articles en el archivo routes.rb
Esta línea genera los métodos y helpers necesarios para trabajar con REST. Cada método/helper en conjunto con un verbo y una URL, apunta a una acción de nuestro controlador:
| Método/helper | Verbo | URL | Acción |
|---|---|---|---|
| articles_path | GET | /articles | index |
| articles_path | POST | /articles | create |
| new_article_path | GET | /articles/new | new |
| article_path(:id => 1) | GET | /articles/1 | show |
| article_path(:id => 1) | PUT | /articles/1 | update |
| edit_article_path(:id => 1) | GET | /articles/1/edit | edit |
| article_path(:id => 1) | DELETE | /articles/1 | destroy |
Nota: también se puede usar _url en lugar de _path.
Entonces, un formulario con REST para actualizar un post quedaría así:
<% form_for @article, :html => { :method => :put } do |f| %>
<p><label for="article_title">Título</label><br/>
<%= f.text_field :title %></p>
<p><label for="article_content">Cuerpo</label><br/>
<%= f.text_area :content, :rows => 5 %></p>
<p><%= submit_tag 'Agregar' %></p>
<% end %>
Esto genera un HTML similar a:
<form action="/articles/1" method="post"> <input name="_method" type="hidden" value="put" /> <p><label for="article_title">Título</label><br/> <input id="article_title" name="article[title]" size="30" type="text" value="Mi primer post" /></p> <p><label for="article_content">Cuerpo</label><br/> <textarea cols="40" id="article_content" name="article[content]" rows="5"></textarea></p> </fieldset> <p><input name="commit" type="submit" value="Agregar" /></p> </form>
Los navegadores actuales sólo soportan los verbos (métodos) POST y GET, por eso rails agrega un hidden field <input name=”_method” type=”hidden” value=”put” /> para simular el método PUT.
En el caso del DELETE sería algo como:
<%= link_to 'Eliminar', @article, :confirm => 'Seguro?', :method => :delete %>
y el HTML generado sería algo como:
<a href="/articles/1" onclick="if (confirm('Seguro?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);f.submit(); };return false;">Eliminar</a>
Aquí lo que hace es crear un form background al darle click al enlace que incluye el mismo hidden field que vimos pero ahora con el valor delete. Y seguro se preguntarán: “El formulario lo crea con javascript al dar click, ¿qué pasa si el usuario tiene el javascript deshabilitado?”; bueno, Ryan Bates explica la respuesta en uno de sus screencasts.
Como mencioné, los navegadores actuales sólo soportan los métodos POST y GET por lo que para estas dos acciones no es necesario especificar el método en el form, <% form_for @article, articles_path do |f| %> tendrá el método POST por default; y <%= link_to ‘Editar’, edit_article_path(@article) %> tendrá el método GET por default.
Hasta aquí lo básico para manejar REST en nuestra aplicación. Ahora veamos cómo hacer nuestros propios helpers para acciones extras.
Acciones personalizadas
Supongamos que en el listado de posts queremos incluir un link para cada post y que al darle click lo publique sin tener que ir al formulario de edición y demás…
Primero debemos regresar al archivo mágico routes.rb y modificar nuestra línea map.resources :articles.
Analicemos un poco:
- Queremos hacer un update del estado del post, así que será un método PUT
- El atributo que queremos modificar es published y le daremos un valor true
- Modificaremos sólo un elemento (miembro) de la colección
- Sería bueno si tuvieramos un helper como publish_post_path(@post) que apuntara a la acción publish
Hmmm… entonces, quedaría:
# config/routes.rb
ActionController::Routing::Routes.draw do |map|
map.resources :articles, :member => { :publish => :put }
end
#articles_controller.rb
class ArticlesController < ApplicationController
def publish
@article = Article.find(params[:id])
if @article.update_attribute(:published, true)
flash[:notice] = 'Post publicado'
redirect_to articles_url
end
end
end
Y con eso ya podemos hacer lo siguiente:
<%# articles/index.erb %> <% for article in @articles -%> <p><%= article.title %> <small><%= link_to 'Publicar', publish_article_path(article), :method => :put %></small></p> <% end -%>
Ahora por ejemplo, si quisieramos listar todos los artículos que no están publicados haríamos algo como:
# config/routes.rb
ActionController::Routing::Routes.draw do |map|
map.resources :articles, :member => { :publish => :put },
:collection => { :unpublished => :get }
end
#articles_controller.rb
class ArticlesController < ApplicationController
# def publish ...
def unpublished
@articles = Article.find_all_by_published(false)
render :action => 'index'
end
end
Como ven, REST es fácil de usar siempre y cuando tengamos claro el tipo de recurso al que queremos acceder y el verbo adecuado para lo que queremos hacer. En el primer caso queríamos modificar (put) un sólo elemento (member), mientras que en el segundo estabamos obteniendo (get) la lista de todos los posts (collection).
Hay mucho más que aprender sobre REST, pero ya saben que para seguir aprendiendo lo único que tenemos que hacer es buscar y leer; hay más información en el API.
NOTA: Los ejemplos aquí expuestos no fueron probados… por lo que es posible que tengan algún pequeño error de dedazo o similar.
Dudas y comentarios bienvenidos, espero les haya sido de utilidad. ![]()
If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.

Ya era hora que alguien escribiera algo acerca de REST con un poco de fundamento y ejemplos. La verdad es que es una putada pq me acabo de introducir a RoR hace nada.
Gracias por este post!