Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of github.com:defaude/asciicasts.com-translations

  • Loading branch information...
commit 94ea3aa344ab8e513c09bf74004e17cf1e4b9deb 2 parents c381758 + 40eb8f8
@eifion authored
View
193 episodes/316 - Private Pub/es.html
@@ -0,0 +1,193 @@
+<p>En el &lt;an href=&quot;http://es.asciicasts.com/episodes/260-mensajeria-asincrona-con-faye&quot;&gt;episodio 260</a> vimos como se pueden actualizar los contenidos del navegador del usuario en tiempo real utilizando <a href="http://faye.jcoglan.com/">Faye</a>. Pero aunque Faye es una soluci&oacute;n muy buena su uso puede acarrear bastante trabajo, especialmente si tenemos requisitos complejos de seguridad. Esto es lo que llev&oacute; a Ryan Bates a crear una gema llamada <a href="https://github.com/ryanb/private_pub">Private Pub</a> que funciona sobre Faye, con el prop&oacute;sito de hacer que fuese m&aacute;s f&aacute;cil publicar y suscribirse a eventos en tiempo real en una aplicaci&oacute;n Rails, y en este episodio veremos c&oacute;mo funciona.</p>
+
+<p>La aplicaci&oacute;n con la que vamos a trabajar es un sencillo <em>chat</em>. Si introducimos un mensaje en el campo de texto del fondo de la p&aacute;gina y hacemos clic en &ldquo;Send&rdquo; el navegador enviar&aacute; una petici&oacute;n AJAX para guardar el mensaje y luego actualizar&aacute; el navegador para que dicho mensaje aparezca en la ventana principal.</p>
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/943/original/E316I01.png" width="800" height="399" alt="Nuestra aplicación de chat."/>
+</div>
+
+<p>Pero hay un problema con nuestra aplicaci&oacute;n. Si hay m&uacute;ltiples clientes de chat abiertos no se actualizar&aacute;n todos en tiempo real cuando se env&iacute;e el mensaje. S&oacute;lo el cliente que envi&oacute; el mensaje lo ver&aacute; aparecer; el resto tendr&aacute; que recargar la p&aacute;gina para verlo. Hay varias soluciones a este problema, una de ellas es hacer que los clientes realicen sondeos peri&oacute;dicos consultando si hay nuevos mensajes cada par de segundos, lo cual no es la mejor idea. Otra soluci&oacute;n es mantener una conexi&oacute;n por <em>socket</em> con el servidor en cada cliente de forma que el servidor pueda avisar a los clientes cuando lleguen nuevos mensajes para que estos aparezcan en tiempo real. El problema con esta soluci&oacute;n es que la arquitectura de Rails no est&aacute; pensada para peticiones de larga duraci&oacute;n.</p>
+
+<p>Faye y Private Pub pueden sernos de ayuda en este escenario pero antes de empezar nuestro repaso veremos c&oacute;mo funciona nuestra aplicaci&oacute;n de <em>chat</em>. Empezaremos con la plantilla de la vista de la p&aacute;gina de <em>chat</em>.</p>
+
+``` /app/views/messages/index.html.erb
+<h1>Chat</h1>
+
+<ul id="chat">
+ <%= render @messages %>
+</ul>
+
+<%= form_for Message.new, remote: true do |f| %>
+ <%= f.text_field :content %>
+ <%= f.submit "Send" %>
+<% end %>
+```
+
+<p>En esta plantilla se usa un parcial llamado <code>messages</code> para mostrar el listado de mensajes y se incluye un formulario para crear nuevos mensajes. Este formulario utiliza la opci&oacute;n <code>remote:true</code> para que la petici&oacute;n se env&iacute;e v&iacute;a AJAX hacia la acci&oacute;n <code>create</code> de <code>MessagesController</code>, que tiene el siguiente aspecto:</p>
+
+
+``` /app/controllers/messages_controller.rb
+class MessagesController < ApplicationController
+ def index
+ @messages = Message.all
+ end
+
+ def create
+ @message = Message.create!(params[:message])
+ end
+end
+```
+
+<p>La acci&oacute;n <code>create</code> es muy sencilla, tan s&oacute;lo crea un nuevo <code>Message</code>. Veamos la plantilla de JavaScript que se devolver&aacute; como respuesta a la llamada AJAX:</p>
+
+``` /app/views/messages/create.js.erb
+$("#chat").append("<%= j render(@message) %>");
+$("#new_message")[0].reset();
+```
+
+<p>Este fragmento de JavaScript a&ntilde;ade el mensaje que se acaba de crear al listado del <em>chat</em> y borra el campo del formulario de nuevo mensaje. Lo que queremos que se haga aqu&iacute; es enviar el mensaje a todos los usuarios del <em>chat</em> para que lo muestren, no s&oacute;lo al que lo envi&oacute; y es para esto para lo que vamos a usar Private Pub.</p>
+
+<h3>Instalaci&oacute;n de Private Pub</h3>
+
+<p>Private Pub se instala de la forma habitual a&ntilde;adiendo la gema al fichero <code>Gemfile</code> de la aplicaci&oacute;n y ejecutando a continuaci&oacute;n <code>bundle</code>. Esto har&aacute; que se instale tambi&eacute;n Faye porque est&aacute; declarado como dependencia.</p>
+
+``` /Gemfile
+source 'http://rubygems.org'
+
+gem 'rails', '3.1.3'
+gem 'sqlite3'
+
+# Gems used only for assets and not required
+# in production environments by default.
+group :assets do
+ gem 'sass-rails', '~> 3.1.5'
+ gem 'coffee-rails', '~> 3.1.1'
+ gem 'uglifier', '>= 1.0.3'
+end
+
+gem 'jquery-rails'
+gem 'private_pub'
+```
+
+<p>A continuaci&oacute;n ejecutamos el generador para crear el fichero de configuraci&oacute;n y un fichero Rackup para lanzar el servidor Faye.</p>
+
+``` terminal
+$ rails g private_pub:install
+ create config/private_pub.yml
+ create private_pub.ru
+```
+
+<p>El servidor Rack se arranca con esta orden:</p>
+
+``` terminal
+$ rackup private_pub.ru -s thin -E production
+>> Thin web server (v1.3.1 codename Triple Espresso)
+>> Maximum connections set to 1024
+>> Listening on 0.0.0.0:9292, CTRL+C to stop
+```
+
+<p>Esta orden arranca Faye usando el servidor Thin en el entorno de producci&oacute;n (lo cual es necesario para que arranque). El &uacute;ltimo paso es poner <code>private_pub</code> en fichero de manifiesto de JavaScript de nuestra aplicaci&oacute;n.</p>
+
+``` /app/assets/javascripts/application.js
+// This is a manifest file that'll be compiled into including all the files listed below.
+// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
+// be included in the compiled file accessible from http://example.com/assets/application.js
+// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+// the compiled file.
+//
+//= require jquery
+//= require jquery_ujs
+//= require private_pub
+//= require_tree .
+```
+
+<p>Podemos incluir este JavaScript en el <em>layout</em> de la aplicaci&oacute;n si estamos con versiones de Rails anteriores a la 3.1.</p>
+
+<h3>Uso de Private Pub en nuestras aplicaciones</h3>
+
+<p>Una vez configurada la carga de Private Pub es f&aacute;cil suscribirse a un canal y publicar notificaciones de actualizaci&oacute;n sobre &eacute;l. Lo &uacute;nico que hay que hacer es suscribirse a un canal en una plantilla de la vista, por ejemplo en nuestra p&aacute;gina de mensajes, invocando <code>subscribe_to</code> y pasando el nombre del canal. El formato de un canal en Faye es como el de una ruta de archivo, nosotros vamos a usar <code>/messages/new</code>.</p>
+
+``` /app/views/messages/index.html.erb
+<h1>Chat</h1>
+
+<ul id="chat">
+ <%= render @messages %>
+</ul>
+
+<%= form_for Message.new, remote: true do |f| %>
+ <%= f.text_field :content %>
+ <%= f.submit "Send" %>
+<% end %>
+
+<%= subscribe_to "/messages/new" %>
+```
+
+<p>Lo siguiente que tenemos que hacer es ir a una plantilla JavaScript que se muestre como resultado de una petici&oacute;n AJAX (como la que tenemos que muestra los nuevos mensajes) y envolver el c&oacute;digo en un bloque <code>publish_to</code>.</p>
+
+``` /app/views/messages/create.js.erb
+<% publish_to "/messages/new" do %>
+ $("#chat").append("<%= j render(@message) %>");
+ $("#new_message")[0].reset();
+<% end %>
+```
+
+<p>El hacer esto quiere decir que este JavaScript no s&oacute;lo se devolver&aacute; al cliente que hizo la petici&oacute;n, sino que ser&aacute; publicada a todos los suscriptores del canal <code>/messages/new</code>. Podemos hacer la prueba ahora mismo. Si abrimos la aplicaci&oacute;n en dos navegadores distintos y enviamos un mensaje en uno de ellos, dicho mensaje aparecer&aacute; instant&aacute;neamente en el otro.</p>
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/944/original/E316I02.png" width="851" height="418" alt="Los mensajes aparecen inmediatamente en todos los clientes."/>
+</div>
+
+<p>Puede ser que no queramos publicar sobre un canal directamente en la respuesta AJAX. Por ejemplo podr&iacute;amos querer publicar desde una acci&oacute;n del controlador. Esto se puede hacer desde Ruby utilizando <code>PrivatePub.publish_to</code>, y pasando el nombre del canal en el que queremos publicar y el c&oacute;digo JavaScript que queremos que se ejecute en todos los clientes suscritos. Demostremos esta funcionalidad devolviendo un <code>alert</code>.</p>
+
+``` /app/controllers/messages_controller.rb
+def create
+ @message = Message.create!(params[:message])
+ PrivatePub.publish_to("/messages/new", "alert('#{@message.content}');")
+end
+```
+
+<p>El <code>alert</code> aparecer&aacute; en ambos navegadores cuando se escriba un mensaje en cualquiera de ellos.</p>
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/945/original/E316I03.png" width="852" height="417" alt="La alerta aparece en ambos navegadores."/>
+</div>
+
+<h3>Manipulaci&oacute;n de datos JSON</h3>
+
+<p>Tambi&eacute;n se puede si lo preferimos trabajar con datos en JSON en lugar de c&oacute;digo JavaScript. Lo &uacute;nico que hace falta hacer es pasar a <code>publish_to</code> un objeto (como un <em>hash</em>) en lugar de una cadena y entonces ser&aacute; convertido a JSON.</p>
+
+``` /app/controllers/messages_controller.rb
+def create
+ @message = Message.create!(params[:message])
+ PrivatePub.publish_to("/messages/new", message: @message)
+end
+```
+
+<p>Con este enfoque tendremos que escribir JavaScript para gestionar el JSON que estamos emitiendo. Lo haremos en el fichero CoffeeScript <code>messages</code>.</p>
+
+``` /app/assets/javascripts/messages.js.coffee
+PrivatePub.subscribe "/messages/new", (data, channel) ->
+ alert data.message.content
+```
+
+<p>Aqu&iacute; llamamos a <code>PrivatePub.subscribe</code>, que recibe un nombre de canal y una funci&oacute;n as&iacute;ncrona que recibe dos argumentos, <code>data</code> y <code>channel</code>. La funci&oacute;n ser&aacute; invocada cada vez que haya una actualizaci&oacute;n con nuevos datos JSON en el canal. En nuestro c&oacute;digo tan s&oacute;lo hacemos <code>alert</code> mostrando el campo <code>message.content</code> de los datos recibidos. Si recargamos las p&aacute;ginas y enviamos otro mensaje veremos la alerta mostrando los datos JSON enviados desde el servidor.</p>
+
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/946/original/E316I04.png" width="800" height="415" alt="La alerta mostrando JSON."/>
+</div>
+
+<p>Una ventaja de Private Pub es que los canales por defecto son privados. Esto quiere decir que no tenemos que preocuparnos de que haya usuarios escuchando en canales a los que no hayan sido expl&iacute;citamente suscritos. Con esto es muy f&aacute;cil crear, por ejemplo, una sala privada de conversaci&oacute;n donde s&oacute;lo pueden escribir y leer los usuarios que se hayan suscrito. Tambi&eacute;n podemos expirar las suscripciones pasado alg&uacute;n tiempo de forma que los usuarios no puedan volver a escuchar mensajes despu&eacute;s de haber terminado la sesi&oacute;n. Todo esto se configura en el fichero <code>private_pub.yml</code>.</p>
+
+``` /config/private_pub.yml
+development:
+ server: "http://localhost:9292/faye"
+ secret_token: "secret"
+test:
+ server: "http://localhost:9292/faye"
+ secret_token: "secret"
+production:
+ server: "http://example.com/faye"
+ secret_token: "210eb617b6ce1c351d986a3185d34025cf42e5091a37502f18f595f7e8773853"
+ signature_expiration: 3600 # one hour
+```
View
231 episodes/318 - Upgrading to Rails 3.2/es.html
@@ -0,0 +1,231 @@
+<p>Rails 3.2 est&aacute; reci&eacute;n salido y hay una anotaci&oacute;n muy interesante <a href="http://weblog.rubyonrails.org/2012/1/20/rails-3-2-0-faster-dev-mode-routing-explain-queries-tagged-logger-store">en el blog oficial</a> que explica algunas de las novedades. Lo m&aacute;s importante de todo es que el entorno de desarrollo carga con mayor velocidad porque s&oacute;lo recarga los archivos que han cambiado desde la &uacute;ltima petici&oacute;n. Tambi&eacute;n hay un nuevo motor de rutas llamado Journey que tambi&eacute;n es m&aacute;s r&aacute;pido. En este episodio veremos c&oacute;mo actualizar una aplicaci&oacute;n de Rails 3.1 a Rails 3.2, as&iacute; como algunas de las nuevas funcionalidades.</p>
+
+<h3>Actualizaci&oacute;n de una aplicaci&oacute;n ya existente</h3>
+
+<p>Para actualizar una aplicaci&oacute;n Rails 3.1 a 3.2 lo primero que tenemos que hacer es modificar el <code>Gemfile</code>.</p>
+
+``` /Gemfile
+source 'http://rubygems.org'
+
+gem 'rails', '3.2.0'
+
+gem 'sqlite3'
+
+# Gems used only for assets and not required
+# in production environments by default.
+group :assets do
+ gem 'sass-rails', " ~> 3.2.3"
+ gem 'coffee-rails', "~> 3.2.1"
+ gem 'uglifier', '>=1.0.3'
+end
+
+gem 'jquery-rails'
+```
+
+<p>Hemos actualizado la versi&oacute;n de la gema a <code>3.2.0</code> y tambi&eacute;n hemos cambiado la gema del grupo de est&aacute;ticos para que los n&uacute;meros de versi&oacute;n coincidan con los que aparecer&iacute;an en una aplicaci&oacute;n Rails 3.2 nueva. Para actualizar todo a la &uacute;ltima versi&oacute;n tenemos que ejecutar <code>bundle update</code>.</p>
+
+<p>Adem&aacute;s de modificar el fichero de gemas hay otra configuraci&oacute;n de entorno extra que nos queda por hacer hasta configurar nuestra aplicaci&oacute;n igual que una nueva en 3.2. En el fichero de configuraci&oacute;n tenemos que a&ntilde;adir estas dos l&iacute;neas.</p>
+
+``` /config/environments/development.rb
+# Raise exception on mass assignment protection for Active Record models
+config.active_record.mass_assignment_sanitizer = :strict
+
+# Log the query plan for queries taking more than this (works
+# with SQLite, MySQL, and PostgreSQL)
+config.active_record.auto_explain_threshold_in_seconds = 0.5
+```
+
+<p>La primera de estas configuraciones establece <code>mass_assignment_sanitizer</code> a <code>:strict</code>. Esto elevar&aacute; una excepci&oacute;n si hay una asignaci&oacute;n masiva de atributos protegidos. La segunda l&iacute;nea establece el umbral de auto-explicaci&oacute;n de consultas a <code>0.5</code>. Esto quiere decir que se ejecutar&aacute; una consulta EXPLAIN contra cualquier consulta a base de datos que supere el medio segundo de tiempo, quedando la informaci&oacute;n guardada en trazas. Es buena idea copiar la opci&oacute;n <code>mass_assignment_sanitizer</code> al entorno de pruebas y tambi&eacute;n eliminar la siguiente l&iacute;nea que ya no se genera por defecto.</p>
+
+``` /config/environments/test.rb
+# Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets
+config.assets.allow_debugging = true
+```
+
+<h3>Consultas EXPLAIN</h3>
+
+<p>Con la aplicaci&oacute;n ya actualizada a Rails 3.2 veremos algunas de las nuevas funcionalidades en la consola de Rails. Ya hemos mencionado que a las consultas que tarden demasiado se les aplicar&aacute; una consulta adicional EXPLAIN, pero podemos activar este comportamiento desde la consola ejecutando <code>explain</code> contra una consulta ActiveRecord.</p>
+
+``` terminal
+1.9.2-p290 :001 > Product.order(:name).explain
+ Product Load (0.6ms) SELECT "products".* FROM "products" ORDER BY name
+ EXPLAIN (0.1ms) EXPLAIN QUERY PLAN SELECT "products".* FROM "products" ORDER BY name
+ => "EXPLAIN for: SELECT \"products\".* FROM \"products\" ORDER BY name\n0|0|0|SCAN TABLE products (~1000000 rows)\n0|0|0|USE TEMP B-TREE FOR ORDER BY\n"
+```
+
+<p>Podemos imprimir la salida de forma m&aacute;s limpia con <code>puts _</code>.</p>
+
+``` terminal
+1.9.2-p290 :002 > puts _
+EXPLAIN for: SELECT "products".* FROM "products" ORDER BY name
+0|0|0|SCAN TABLE products (~1000000 rows)
+0|0|0|USE TEMP B-TREE FOR ORDER BY
+```
+
+<p>En este caso la consulta EXPLAIN no es muy interesante porque se trata de una consulta muy sencilla pero esta funcionalidad es mucho m&aacute;s &uacute;til con consultas JOIN complicadas. Si hay alg&uacute;n punto en nuestra aplicaci&oacute;n que sabemos que lanza una consulta lenta y no queremos que se haga un EXPLAIN autom&aacute;ticamente podemos rodear la consulta en un bloque <code>silence_auto_explain</code> de la siguiente manera:</p>
+
+``` terminal
+1.9.2-p290 :003 > ActiveRecord::Base.silence_auto_explain { Product.order(:name) }
+```
+
+<p>La consulta dentro del bloque no generar&aacute; un EXPLAIN, independientemente de lo que tarde en ejecutarse.</p>
+
+<h3>Nuevos m&eacute;todos ActiveRecord</h3>
+
+<p>Otra funcionalidad muy &uacute;til de Rails 3.2 es el m&eacute;todo <code>pluck</code>, que nos permite pasar un nombre de columna y devolver&aacute; los valores de dicha columna.</p>
+
+``` terminal
+1.9.2-p290 :005 > Product.pluck(:name)
+ (0.2ms) SELECT name FROM "products"
+ => ["Settlers of Catan", "Flux Capacitor", "Technodrome", "Agricola", "Millennium Falcon", "Ryan's Cheesecake", "Answer to Everything"]
+```
+
+<p>Podemos hacerlo con cualquier columna para recuperar todos los valores en un <em>array</em> con el tipo de datos apropiado.</p>
+
+``` terminal
+1.9.2-p290 :007 > Product.pluck(:id)
+ (0.2ms) SELECT id FROM "products"
+ => [1, 2, 3, 4, 5, 6, 7]
+```
+
+<p>De forma similar si utilizamos la cl&aacute;usula <code>select</code> para restringir qu&eacute; columnas hay que recuperar, ahora existe un nuevo m&eacute;todo <code>uniq</code> que podemos usar por ejemplo para devolver un producto para cada nombre &uacute;nico.</p>
+
+``` terminal
+1.9.2-p290 :009 > Product.select(:name).uniq
+ Product Load (0.3ms) SELECT DISTINCT name FROM "products"
+ => [#<Product name: "Agricola">, #<Product name: "Answer to Everything">, #<Product name: "Flux Capacitor">, #<Product name: "Millennium Falcon">, #<Product name: "Ryan's Cheesecake">, #<Product name: "Settlers of Catan">, #<Product name: "Technodrome">]
+```
+
+<p>Otra nueva funcionalidad, <code>first_or_create</code> est&aacute; pensada para funcionar con la cl&aacute;usula <code>where</code>.</p>
+
+``` terminal
+1.9.2-p290 :010 > Product.where(name: "Foo").first_or_create!
+```
+
+<p>En este caso hemos usado el m&eacute;todo en su versi&oacute;n con admiraci&oacute;n para que se eleve una excepci&oacute;n si existe alg&uacute;n error de validaci&oacute;n. El c&oacute;digo anterior funciona de forma similar a <code>find_or_create_by_name</code>. La primera vez que se ejecute crear&aacute; un nuevo <code>Product</code> con el <code>name</code> correspondiente (asumiendo que no existe ya uno); cuando volvamos a ejecutarlo devolver&aacute; el producto correspondiente. Lo interesante de este enfoque es que se pueden pasar atributos adicionales a la llamada <code>create</code>, de la siguiente manera:</p>
+
+``` terminal
+1.9.2-p290 :011 > Product.where(name: "Foo").first_or_create!(price: 5)
+```
+
+<p>Los registros que se creen tendr&aacute;n estos atributos, pero dichos atributos no ser&aacute;n tenidos en cuenta cuando se busca el <code>Product</code>.</p>
+
+<p>El &uacute;ltimo m&eacute;todo nuevo que veremos se llama <code>safe_constantize</code>, que es un m&eacute;todo implementado sobre las cadenas.</p>
+
+``` terminal
+1.9.2-p290 :007 > "Product".safe_constantize
+ => Product(id: integer, name: string, price: decimal, description: text, discontinued: boolean, created_at: datetime, updated_at: datetime)
+```
+
+<p>El m&eacute;todo devuelve la constante correspondiente si es que existe. La diferencia de este m&eacute;todo y el <code>constantize</code> normal es que devuelve <code>nil</code> si no se encuentra la constante en lugar de lanzar una excepci&oacute;n.</p>
+
+<h3>Nuevas funcionalidades en las migraciones</h3>
+
+<p>Veamos ahora algunas nuevas opciones que podemos usar cuando generamos migraciones. Supongamos que vamos a generar la migraci&oacute;n de un nuevo modelo <code>ProductVariation</code>. He aqu&iacute; nuestra migraci&oacute;n.</p>
+
+``` terminal
+$ rails g model product_variation product_id:integer:index name 'price:decimal{7,2}'
+```
+
+<p>La migraci&oacute;n utiliza tres nuevas funcionalidades. Queremos que una <code>ProductVariation</code> pertenezca a un <code>Product</code> por lo que hemos especificado <code>product_id</code> como una de las columnas. En Rails 3.2 podemos a&ntilde;adir una nueva opci&oacute;n <code>index</code> para generar autom&aacute;ticamente un &iacute;ndice sobre esta columna.</p>
+
+<p>Queremos que la <code>ProductVariation</code> disponga de una columna <code>name</code> de tipo cadena. Por lo general utilizar&iacute;amos <code>name:string</code> en nuestra migraci&oacute;n pero ahora <code>string</code> es el tipo por defecto por lo que no tenemos que hacerlo. Por &uacute;ltimo si estamos definiendo un campo <code>decimal</code> podemos pasar opciones para especificar la precisi&oacute;n y la escala de dicho tipo. N&oacute;tese que es necesario entrecomillar esta parte de la migraci&oacute;n para que la <em>shell</em> no intente modificarla.</p>
+
+<p>He aqu&iacute; el aspecto que tiene la migraci&oacute;n generada.</p>
+
+``` /db/migrations/20120101000000_create_product_variations.rb
+class CreateProductVariations < ActiveRecord::Migration
+ def change
+ create_table :product_variations do |t|
+ t.integer :product_id
+ t.string :name
+ t.decimal :price, :precision => 7, :scale => 2
+
+ t.timestamps
+ end
+ add_index :product_variations, :product_id
+ end
+end
+```
+
+<p>En la migraci&oacute;n puede verse que existe un &iacute;ndice definido sobre <code>product_id</code>, que el campo <code>name</code> ha sido asignado por defecto como cadena y que el campo <code>price</code> tiene definida su precisi&oacute;n y escala.</p>
+
+<p>Hablando de generadores puede ser que tengamos algunas opciones favoritas a la hora de generar una aplicaci&oacute;n Rails. Por ejemplo podemos escoger siempre la misma base de datos o excluir los tests de unidad. Se puede hacer que estas sean las opciones por defecto guard&aacute;ndolas en un fichero <code>.railsrc</code> en nuestro directorio.</p>
+
+``` terminal
+$ echo -d postgresql -T > ~/.railsrc
+```
+
+<p>Cuando creemos una nueva aplicaci&oacute;n Rails estas opciones se a&ntilde;adir&aacute;n autom&aacute;ticamente.</p>
+
+``` terminal
+$ rails new blog
+Using -d postgresql -T from /Users/eifion/.railsrc
+```
+
+<h3>Almacenamiento clave-valor</h3>
+
+<p>ActiveRecord viene con una nueva manera de definir almacenamiento de pares clave-valor en los modelos. Supongamos que en nuestro modelo <code>ProductVariation</code> tenemos algunos atributos como <code>colour</code> y <code>size</code> y no queremos columnas separadas de base de datos para cada uno de ellos. Podemos utilizar el nuevo m&eacute;todo <code>store</code> para guardar dichos valores en una &uacute;nica columna. </p>
+
+``` /app/models/product_variation.rb
+class ProductVariation < ActiveRecord::Base
+ store :properties, accessors: [:colour, :size]
+end
+```
+
+<p>El primer argumento que se pasa contiene el nombre de la columna sobre la que se almacenar&aacute;n los valores y en el segundo se definen las propiedades que queremos guardar. Tenemos que crear la columna en base de datos por lo que nos har&aacute; falta una migraci&oacute;n.</p>
+
+
+``` terminal
+$ rails g migration add_properties_to_product_variations properties:text
+```
+
+<p>No debemos olvidarnos de ejecutar <code>rake db:migrate</code> para a&ntilde;adir la columna a la base de datos.</p>
+
+<p>Veamos una demostraci&oacute;n de esto en la consola. Podemos crear una nueva <code>ProductVariation</code> y darle los atributos <code>colour</code> y <code>size</code> igual que har&iacute;amos con los atributos normales.</p>
+
+``` terminal
+Loading development environment (Rails 3.2.0)
+1.9.2-p290 :001 > p = ProductVariation.new(colour: 'blue', size: 3)
+ => #<ProductVariation id: nil, product_id: nil, name: nil, price: nil, created_at: nil, updated_at: nil, properties: {:colour=>"blue", :size=>3}>
+```
+
+<p>Podemos acceder a estos atributos igual que al resto.</p>
+
+
+``` terminal
+1.9.2-p290 :003 > p.colour
+ => "blue"
+```
+
+<p>Tambi&eacute;n podemos acceder a ellos mediante el <em>hash</em> <code>properties</code>.</p>
+
+``` terminal
+1.9.2-p290 :004 > p.properties[:colour]
+ => "blue"
+```
+
+<p>No podremos hacer b&uacute;squedas sobre estos atributos porque no mapean directamente sobre columnas de la base de datos pero se trata de una forma muy conveniente de acceder a un conjunto de atributos.</p>
+
+<h3>Etiquetado de trazas</h3>
+
+<p>Todav&iacute;a nos queda una &uacute;ltima funcionalidad por ver: las trazas etiquetadas. Se trata de algo que normalmente s&oacute;lo se hace en modo de producci&oacute;n pero para la demostraci&oacute;n lo vamos a incorporar a nuestro entorno de desarrollo. Esto se hace con la opci&oacute;n de configuraci&oacute;n <code>log_tags</code> a la que le establecemos un <em>array</em> de atributos que son los nombres de los m&eacute;todos que se invocar&aacute;n sobre la petici&oacute;n.</p>
+
+``` /config/environments/development.rb
+config.log_tags = [:uuid, :remote_ip]
+```
+
+<p>Hemos usado <code>uuid</code> que es un nuevo m&eacute;todo en Rails 3.2 que devuelve un identificador &uacute;nico de petici&oacute;n y que nos sirve para determinar la petici&oacute;n a partir de la que se origin&oacute; la traza. La otra es la direcci&oacute;n IP remota. Si ahora arrancamos el servidor de nuevo y lanzamos una petici&oacute;n las l&iacute;neas de la traza aparecer&aacute;n etiquetada con estos valores.</p>
+
+``` log
+[ab939dfca5d57843ea4c695cab6f721d] [127.0.0.1]
+
+Started GET "/" for 127.0.0.1 at 2012-01-27 21:52:58 +0000
+[ab939dfca5d57843ea4c695cab6f721d] [127.0.0.1] Processing by ProductsController#index as HTML
+[ab939dfca5d57843ea4c695cab6f721d] [127.0.0.1] Product Load (0.3ms) SELECT "products".* FROM "products"
+[ab939dfca5d57843ea4c695cab6f721d] [127.0.0.1] Rendered products/index.html.erb within layouts/application (22.0ms)
+[ab939dfca5d57843ea4c695cab6f721d] [127.0.0.1] Completed 200 OK in 81ms (Views: 73.1ms | ActiveRecord: 0.3ms)
+[98eec5f8976586c1165b981797086b6a] [127.0.0.1]
+```
+
+<p>Esto resulta &uacute;til en producci&oacute;n cuando hay varias instancias de Rails escribiendo sobre los archivos de traza, ahora podremos separar las entradas del <em>log</em> que han sido generadas por diferentes peticiones concretas.</p>
View
205 episodes/320 - JBuilder/es.html
@@ -0,0 +1,205 @@
+<p>Si echamos un vistazo al <code>Gemfile</code> de una aplicaci&oacute;n Rails 3.2 veremos que en los comentarios se hace menci&oacute;n a una gema que no aparec&iacute;a en las versiones anteriores, llamada <a href="https://github.com/rails/jbuilder">Jbuilder</a>.</p>
+
+``` /Gemfile
+# To use Jbuilder templates for JSON
+# gem 'jbuilder'
+```
+
+<p>Jbuilder es un motor de plantillas que sirve para generar respuestas en JSON. Fue recientemente creada por David Heinemeier Hansson, pero en lugar de incluirla en Rails 3.2 David prefiri&oacute; publicarla por separado en forma de gema. Este enfoque permite su uso con versiones anteriores. Jbuilder proporciona un DSL para generar ficheros JSON de forma similar a XML Builder, y en este episodio veremos c&oacute;mo se usa.</p>
+
+<h3>Respuestas JSON desde la aplicaci&oacute;n</h3>
+
+<p>Como demonstraci&oacute;n de Jbuilder vamos a utilizar una aplicaci&oacute;n sencilla de <em>blog</em>. La aplicaci&oacute;n dispone de varios art&iacute;culos, y querr&iacute;amos proporcionar una representaci&oacute;n en JSON de dichos art&iacute;culos simplemente a&ntilde;adiendo <code>.json</code> a la URL de cada art&iacute;culo. Si ahora mismo hacemos esto veremos que aparece un error porque no hemos a&ntilde;adido esta funcionalidad.</p>
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/958/original/E320I01.png" width="800" height="280" alt="La representación en JSON no funciona tal cual."/>
+</div>
+
+<p>Se puede a&ntilde;adir esta funcionalidad sin emplear Jbuilder a&ntilde;adiendo un bloque <code>respond_to</code> a la acci&oacute;n <code>show</code> en <code>ArticlesController</code>.</p>
+
+``` /app/controllers/articles_controller.rb
+def show
+ @article = Article.find(params[:id])
+ respond_to do |format|
+ format.html
+ format.json { render json: @article }
+ end
+end
+```
+
+<p>Al recargar la p&aacute;gina veremos la representaci&oacute;n en JSON del art&iacute;culo.</p>
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/959/original/E320I02.png" width="800" height="280" alt="Ya funciona la representación en formato JSON."/>
+</div>
+
+<h3>Personalizaci&oacute;n de la respuesta</h3>
+
+<p>El JSON que se devuelve incluye todos los atributos del art&iacute;culo pero, &iquest;y si queremos personalizarlos? Aqu&iacute; es donde se nos complican las cosas. Podemos invocar <code>as_json</code> en el art&iacute;culo para controlar lo que se devuelve. Supongamos que queremos mostrar los campos <code>id</code>, <code>name</code> y <code>content</code> del art&iacute;culo, as&iacute; como su autor y los mismo tres campos de los comentarios.</p>
+
+```/app/controllers/articles_controller.rb
+def show
+ @article = Article.find(params[:id])
+ respond_to do |format|
+ format.html
+ format.json { render json: @article.as_json(only: [:id, :name, :content], include: [:author, {comments: {only:[:id, :name, :content]}}]) }
+ end
+end
+```
+
+<p>Prob&eacute;moslo recargando la p&aacute;gina. Al hacerlo veremos la nueva respuesta en JSON que hemos personalizado incluyendo los registros <code>Author</code> y <code>Comment</code>.</p>
+
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/960/original/E320I03.png" width="800" height="280" alt="La representación en JSON ahora incluye la información relacionada del autor y los comentarios."/>
+</div>
+
+<h3>Uso de Jbuilder</h3>
+
+<p>Aunque esto funciona el c&oacute;digo que hemos terminado usando no es muy bonito. Podr&iacute;amos redefinir <code>as_json</code> en el modelo, pero tampoco quedar&iacute;a mucho mejor. Aqu&iacute; es donde entra en juego Jbuilder. Para su instalaci&oacute;n simplemente tenemos que quitar el comentario en la l&iacute;nea correspondiente del <code>Gemfile</code> y ejecutar <code>bundle</code>.</p>
+
+```/Gemfile
+# To use Jbuilder templates for JSON
+gem 'jbuilder'
+```
+
+<p>Volviendo al controlador podemos eliminar la llamada a <code>respond_to</code> y volver al comportamiento por defecto, que es buscar la plantilla correspondiente al formato solicitado.</p>
+
+```/app/controllers/articles_controller.rb
+def show
+ @article = Article.find(params[:id])
+end
+```
+
+<p>A continuaci&oacute;n vamos a crear una plantilla JSON en el directorio <code>/app/views/articles</code>, en la que podremos usar c&oacute;digo Ruby para definir la salida JSON. Tenemos acceso a un objeto <code>json</code> sobre el que podemos definir de la siguiente manera:</p>
+
+``` /app/views/articles/show.json.jbuilder
+json.id @article.id
+json.name @article.name
+```
+
+<p>Tenemos que reiniciar el servidor despu&eacute;s de haber instalado la gema, tras lo cual podremos recargar la p&aacute;gina para ver la salida que hemos preparado.</p>
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/961/original/E320I04.png" width="800" height="280" alt="Nuestra respuesta."/>
+</div>
+
+<p>Puede resultar complicado enumerar cada atributo por separado de esta forma. En vez de esto podemos llamar a <code>extract!</code> sobre el objeto JSON y pasar el objeto y una lista de los m&eacute;todos o atributos que queramos recuperar.</p>
+
+``` /app/views/articles/show.json.jbuilder
+json.extract! @article, :id, :name, :published_at
+```
+
+<p>Disponemos de una sintaxis alternativa para hacer esto:</p>
+
+``` /app/views/articles/show.json.jbuilder
+json.(@article, :id, :name, :published_at)
+```
+
+<p>Esto s&oacute;lo funciona en Ruby 1.9 porque invoca a <code>call</code> sobre el objeto en segundo plano pas&aacute;ndole el m&eacute;todo <code>extract!</code>. Una de las ventajas de mostrar JSON en la plantilla de la vista de esta forma es que tenemos acceso a los m&eacute;todos <em>helper</em>, lo cual es especialmente &uacute;til para mostrar URLs. Supongamos que s&oacute;lo queremos incluir la URL de edici&oacute;n en el JSON si el usuario es administrador. Tambi&eacute;n tendremos acceso al m&eacute;todo <code>current_user</code> si la soluci&oacute;n de autenticaci&oacute;n que estamos usando lo incluye como m&eacute;todo <em>helper</em>.</p>
+
+``` /app/views/articles/show.json.jbuilder
+json.(@article, :id, :name, :published_at)
+json.edit_url edit_article_url(@article) if current_user.admin?
+```
+
+<p>Como el usuario que tiene sesi&oacute;n iniciada es administrador, el JSON deber&iacute;a mostar el enlace.</p>
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/962/original/E320I05.png" width="800" height="280" alt="Inclusión de un enlace de edición."/>
+</div>
+
+<h3>Anidamiento</h3>
+
+<p>En nuestra aplicaci&oacute;n un <code>Article</code> pertenece a un <code>Author</code>. Si queremos incluir los atributos de un autor, una de las formas de hacerlo es la siguiente:</p>
+
+``` /app/views/articles/show.json.jbuilder
+json.(@article, :id, :name, :published_at)
+json.edit_url edit_article_url(@article) if current_user.admin?
+
+json.author @article.author, :id, :name
+```
+
+<p>Con esto anidaremos los atributos de <code>Author</code> tal y como queremos.</p>
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/963/original/E320I06.png" width="800" height="280" alt="Ahora se anidan los atributos del autor."/>
+</div>
+
+<p>Podemos hacer cosas mas complejas, supongamos que queremos asignar una URL al autor, podemos pasar un bloque al <code>author</code> de la siguiente forma:</p>
+
+``` /app/views/articles/show.json.jbuilder
+json.(@article, :id, :name, :published_at)
+json.edit_url edit_article_url(@article) if current_user.admin?
+
+json.author do |json|
+ json.(@article.author, :id, :name)
+ json.url author_url(@article.author)
+end
+```
+
+<p>Si ahora recargamos la p&aacute;gina veremos los anidados los atributos del autor, incluyendo la URL.</p>
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/964/original/E320I07.png" width="800" height="280" alt="La respuesta incluye la URL del autor."/>
+</div>
+
+<p>Podemos hacer lo mismo con las asociaciones <code>has_many</code>. Por ejemplo un art&iacute;culo tiene muchos comentarios, y podemos a&ntilde;adirlos directamente y mostrar los atributos que queramos que sean visibles.</p>
+
+``` /app/views/articles/show.json.jbuilder
+json.(@article, :id, :name, :published_at)
+json.edit_url edit_article_url(@article) if current_user.admin?
+
+json.author do |json|
+ json.(@article.author, :id, :name)
+ json.url author_url(@article.author)
+end
+
+json.comments @article.comments, :id, :name, :content
+```
+
+<p>Con esto tambi&eacute;n se incluyen los comentarios.</p>
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/965/original/E320I08.png" width="800" height="280" alt="Ahora se incluyen los comentarios."/>
+</div>
+
+<p>El enfoque es un poco diferente si tenemos que usar la sintaxis de bloque porque tenemos un <em>array</em> de comentarios y tenemos que iterar sobre cada elemento. Lo que hacemos es pasar los objetos <code>json</code> y <code>comment</code> al bloque lo que nos dar&aacute; el acceso necesario:</p>
+
+``` /app/views/articles/show.json.jbuilder
+json.(@article, :id, :name, :published_at)
+json.edit_url edit_article_url(@article) if current_user.admin?
+
+json.author do |json|
+ json.(@article.author, :id, :name)
+ json.url author_url(@article.author)
+end
+
+json.comments @article.comments do |json, comment|
+ json.(comment , :id, :name, :content)
+end
+```
+
+<p>Esto hace b&aacute;sicamente lo mismo que el c&oacute;digo anterior.</p>
+
+<h3>Parciales</h3>
+
+<p>Al estar rellenando el bloque de comentarios con bastante detalle puede ser que nos interese duplicar esta funcionalidad en alg&uacute;n otro sitio, para lo que podemos usar parciales. Funcionan de forma similar a las vistas normales, tenemos que llamar a <code>partial!</code> en el objeto <code>json</code> y pasar la ruta al parcial o tan s&oacute;lo un objeto, en este caso un comentario.</p>
+
+``` /app/views/articles/show.json.jbuilder
+json.comments @article.comments do |json, comment|
+ json.partial! comment
+end
+```
+
+<p>Esto har&aacute; que se busque en el directorio <code>app/views/comments</code> un parcial llamado <code>_comment.json.jbuilder</code>. En este parcial tenemos acceso al mismo objeto <code>json</code> y podemos hacer lo mismo que har&iacute;amos en el bloque de comentario. Tambi&eacute;n tenemos acceso al objeto comentario porque tambi&eacute;n lo hemos pasado en la llamada a <code>partial!</code>.</p>
+
+``` /app/views/comments/_comment.json.jbuilder
+json.(comment, :id, :name, :content)
+```
+
+<p>Esto mostrar&aacute; el mismo JSON que ten&iacute;amos antes.</p>
+
+<h3>Alternativas</h3>
+
+<p>Jbuilder no es la &uacute;nica gema que hace este tipo de cosas. Al final de su <a href="https://github.com/rails/jbuilder/blob/master/README.md">README</a> se enumeran varias alternativas a considerar. <a href="https://github.com/nesquena/rabl">RABL</a> es la m&aacute;s popular, por lo que la veremos en un pr&oacute;ximo episodio.</p>
View
203 episodes/322 - RABL/es.html
@@ -0,0 +1,203 @@
+<p>Nuestras aplicaciones pueden devolver datos JSON de nuestros modelos de varias maneras. Se puede redefinir el m&eacute;todo <code>as_json</code> del modelo o utilizar la gema <a href="https://github.com/rails/jbuilder">Jbuilder</a> tal y como vimos en el <a href="http://railscasts.com/episodes/320-jbuilder">episodio 320</a>. Otra soluci&oacute;n muy popular es la gema <a href="https://github.com/nesquena/rabl">RABL</a>. RABL significa Ruby API Builder Language y su funcionalidad algo m&aacute;s completa que el resto de soluciones.</p>
+
+<p>En este episodio veremos c&oacute;mo funciona RABL, utilizando la misma aplicaci&oacute;n de ejemplo del episodio dedicado a Jbuilder, y as&iacute; podremos ver mejor las diferencias entre ambas librer&iacute;as. La aplicaci&oacute;n es una aplicaci&oacute;n de <em>blog</em> que tiene varios art&iacute;culos y queremos ver los datos de cada art&iacute;culo en formato JSON a&ntilde;adiendo <code>.json</code> a la URL de dicho art&iacute;culo. Si ahora mismo hacemos esto veremos un mensaje de error porque la aplicaci&oacute;n no sabe c&oacute;mo responder a peticiones JSON.</p>
+
+<div class="imageWrapper">
+ <img src="http://asciicasts.com/system/photos/976/original/E322I01.png" width="800" height="393" alt="Nuestra aplicación de blog."/>
+</div>
+
+<h3>En marcha con RABL</h3>
+
+<p>Para hacer esto podr&iacute;amos modificar <code>ArticlesController</code>, asegur&aacute;ndonos de que la acci&oacute;n <code>show</code> responde a las peticiones JSON y luego devolver una representaci&oacute;n en JSON del art&iacute;culo, pero en lugar de esto en este episodio vamos a usar RABL. Se trata de una gema que se instala de la forma habitual, a&ntilde;adi&eacute;ndola al <code>Gemfile</code> y ejecutando <code>bundle</code>.</p>
+
+``` /Gemfile
+gem 'rabl'
+```
+
+<p>De forma an&aacute;loga a Jbuilder RABL incluye un gestor de plantillas por lo que podemos definir la respuesta en JSON en la capa de la vista. Creemos una plantilla para la representaci&oacute;n en JSON de un art&iacute;culo. Podemos hacerlo con c&oacute;digo Ruby utilizando el DSL de RABL.</p>
+
+``` /app/views/articles/show.json.rabl
+object @article
+attributes :id, :name, :published_at
+```
+
+<p>Lo primero que aparece en una plantilla RABL por lo general es una llamada a <code>object</code>, a la que se la pasa el objeto sobre el que queremos trabajar. Luego llamamos a <code>attributes</code> para definir qu&eacute; atributos queremos devolver. Ya podemos visitar la URL del art&iacute;culo en JSON y podemos ver que se devuelve el JSON que hemos definido en la plantilla.</p>
+
+``` terminal
+$ curl http://localhost:3000/articles/1.json
+{"article":{"id":1,"name":"Superman","published_at":"2012-01-19T18:38:50Z"}}
+```
+
+<p>Si se quieren especificar atributos m&aacute;s complejos podemos utilizar el m&eacute;todo <code>node</code> y pasarle un nombre y un bloque, de forma que se usar&aacute; como valor lo que devuelva el bloque.</p>
+
+``` /app/views/articles/show.json.rabl
+object @article
+attributes :id, :name, :published_at
+node(:edit_url) { "..." }
+```
+
+<p>Con esto a&ntilde;adiremos un atributo llamado <code>edit_url</code> al JSON.</p>
+
+``` terminal
+$ curl http://localhost:3000/articles/1.json
+{"article":{"id":1,"name":"Superman","published_at":"2012-01-19T18:38:50Z","edit_url":"..."}}
+```
+
+<p>En las plantillas de RABL tenemos acceso a los m&eacute;todos <em>helper</em> por lo que podemos usar <code>edit_article_url</code> para obtener la URl para editar un art&iacute;culo y <code>current_user</code> de forma que s&oacute;lo mostremos esta URL si el usuario dispone de privilegios de administraci&oacute;n (asumiendo que la soluci&oacute;n de autenticaci&oacute;n que usamos dispone de un m&eacute;todo llamado <code>current_user</code>)</p>
+
+``` /app/views/articles/show.json.rabl
+object @article
+attributes :id, :name, :published_at
+if current_user.admin?
+ node(:edit_url) { edit_article_url(@article) }
+end
+```
+
+<p>Pero esto tiene un problema, no es buena pr&aacute;ctica usar la variable de instancia del art&iacute;culo en <code>edit_article_url</code>, deber&iacute;amos utilizar el objeto de art&iacute;culo que se pasa al bloque.</p>
+
+``` /app/views/articles/show.json.rabl
+object @article
+attributes :id, :name, :published_at
+if current_user.admin?
+ node(:edit_url) { |article| edit_article_url(article) }
+end
+```
+
+<p>El objeto que se le pasa al bloque es el mismo objeto que se le pasa al m&eacute;todo <code>object</code>. Hay una raz&oacute;n importante que veremos m&aacute;s adelante por la que es mejor usar el objeto pasado al bloque. Si vemos el JSON del art&iacute;culo veremos el atributo <code>edit_url</code> con el valor correcto.</p>
+
+``` terminal
+$ curl http://localhost:3000/articles/1.json
+{"article":{"id":1,"name":"Superman","published_at":"2012-01-19T18:38:50Z","edit_url":"http://localhost:3000/articles/1/edit"}}
+```
+
+<h3>Registros asociados</h3>
+
+<p>Es f&aacute;cil incluir datos de los registros asociados, si queremos hacerlo. En nuestra aplicaci&oacute;n un <code>Article</code> pertenece a un <code>Author</code> y tiene muchos <code>Comments</code>. Podemos utilizar el m&eacute;todo <code>child</code> de RABL para incluir la informaci&oacute;n correspondiente a estos modelos asociados.</p>
+
+``` /app/views/articles/show.json.rabl
+object @article
+attributes :id, :name, :published_at
+if current_user.admin?
+ node(:edit_url) { |article| edit_article_url(article) }
+end
+
+child :author do
+ attributes :id, :name
+ node(:url) { |author| author_url(author) }
+end
+```
+
+<p>El c&oacute;digo para generar el JSON del autor asociado es muy similar al c&oacute;digo necesario para generar el JSON del art&iacute;culo. La &uacute;nica diferencia es que al bloque del nodo se le pasa un autor en lugar de un art&iacute;culo. Si ahora abrimos el JSON veremos, como es de esperar, los detalles del autor del art&iacute;culo.</p>
+
+``` terminal
+$ curl http://localhost:3000/articles/1.json
+{"article":{"id":1,"name":"Superman","published_at":"2012-01-19T18:38:50Z","edit_url":"http://localhost:3000/articles/1/edit","author":{"id":2,"name":"Clark Kent","url":"http://localhost:3000/authors/2"}}}
+```
+
+<p>Podemos hacer lo mismo con la asociaci&oacute;n <code>Comments</code> aunque como estamos tratando con una relaci&oacute;n <code>has_many</code> tenemos que usar el nombre en plural.</p>
+
+``` /app/views/articles/show.json.rabl
+object @article
+attributes :id, :name, :published_at
+if current_user.admin?
+ node(:edit_url) { |article| edit_article_url(article) }
+end
+
+child :author do
+ attributes :id, :name
+ node(:url) { |author| author_url(author) }
+end
+
+child :comments do
+ attributes :id, :name, :content
+end
+```
+
+<p>En la respuesta JSON los comentarios aparecer&aacute;n anidados en un <em>array</em>, no como un registro sencillo como el autor.</p>
+
+
+``` terminal
+$ curl http://localhost:3000/articles/1.json
+{"article":{"id":1,"name":"Superman","published_at":"2012-01-19T18:38:50Z","edit_url":"http://localhost:3000/articles/1/edit","author":{"id":2,"name":"Clark Kent","url":"http://localhost:3000/authors/2"},"comments":[{"comment":{"id":1,"name":"Lois Lane","content":"Does anyone know where I can find Superman?"}},{"comment":{"id":2,"name":"Lex Luthor","content":"I have some Kryptonite for you Superman!"}}]}}
+```
+
+<h3>Reutilizaci&oacute;n de plantillas</h3>
+
+<p>Hemos adaptado los datos JSON que generamos a nuestro art&iacute;culo pero, &iquest;y si queremos generar la misma salida en alg&uacute;n otro sitio de nuestra aplicaci&oacute;n? Podr&iacute;amos querer que la acci&oacute;n <code>index</code> de <code>ArticlesController</code> mostrase la misma salida en JSON pero para todos los art&iacute;culos. Aqu&iacute; es donde RABL resulta m&aacute;s brillante; lo &uacute;nico que tenemos que hacer es generar una plantilla RABL para la acci&oacute;n <code>index</code>.</p>
+
+``` /app/views/articles/index.json.rabl
+collection @articles
+
+extends "articles/show"
+```
+
+<p>Al trabajar con m&uacute;ltiples art&iacute;culos utilizaremos <code>collection</code> en lugar de <code>object</code>. Podr&iacute;amos definir los atributos que queramos igual que en la plantilla anterior, pero como queremos generar el mismo JSON vamos a reutilizar la misma plantilla llamando a <code>extends</code> y pas&aacute;ndole el nombre. Si ahora abrimos <code>articles.json</code> veremos los datos en JSON de todos los art&iacute;culos.</p>
+
+``` terminal
+$ curl http://localhost:3000/articles.json
+[{"article":{"id":1,"name":"Superman","published_at":"2012-01-19T18:38:50Z","edit_url":"http://localhost:3000/articles/1/edit","author":{"id":2,"name":"Clark Kent","url":"http://localhost:3000/authors/2"},"comments":[{"comment":{"id":1,"name":"Lois Lane","content":"Does anyone know where I can find Superman?"}},{"comment":{"id":2,"name":"Lex Luthor","content":"I have some Kryptonite for you Superman!"}}]}},{"article":{"id":2,"name":"Krypton","published_at":"2012-01-05T18:38:50Z","edit_url":"http://localhost:3000/articles/2/edit","author":{"id":2,"name":"Clark Kent","url":"http://localhost:3000/authors/2"},"":[]}},{"article":{"id":3,"name":"Batman & Robin","published_at":"2012-01-26T18:38:50Z","edit_url":"http://localhost:3000/articles/3/edit","author":{"id":1,"name":"Bruce Wayne","url":"http://localhost:3000/authors/1"},"comments":[{"comment":{"id":3,"name":"The Joker","content":"Haha, Batman, you will see your bat signal tonight!"}},{"comment":{"id":4,"name":"Robin","content":"Enough with the games Joker."}},{"comment":{"id":5,"name":"Riddler","content":"Did someone say games?"}}]}}]
+```
+
+<p>La posibilidad de reutilizar plantillas de esta manera es la raz&oacute;n por la que debemos minimizar el uso de variables de instancia en nuestras plantillas RABL. Como s&oacute;lo usamos la variable <code>@article</code> en la plantilla <code>show</code> cuando definimos el objeto, resulta m&aacute;s f&aacute;cil reutilizar esta plantilla porque en la llamada a <code>node</code> estamos usando el art&iacute;culo en lugar de la variable de instancia.</p>
+
+<h3>Nodos ra&iacute;z</h3>
+
+<p>Puede comprobarse que el JSON generado por RABL incluye el nombre del modelo como nodo ra&iacute;z.</p>
+
+``` terminal
+$ curl http://localhost:3000/articles/1.json
+{"article":{"id":1,"name":"Superman","published_at":"2012-01-19T18:38:50Z","edit_url":"http://localhost:3000/articles/1/edit","author":{"id":2,"name":"Clark Kent","url":"http://localhost:3000/authors/2"},"comments":[{"comment":{"id":1,"name":"Lois Lane","content":"Does anyone know where I can find Superman?"}},{"comment":{"id":2,"name":"Lex Luthor","content":"I have some Kryptonite for you Superman!"}}]}}
+```
+
+<p>Esto a veces puede no interesar. En Rails 3.1 la salida por defecto en JSON no incluye el elemento ra&iacute;z, y si queremos que RABL haga lo mismo tenemos que hacerlo por configuraci&oacute;n. Podemos hacerlo en un nuevo fichero en el directorio <code>config/initializers</code>, asignando a <code>include_json_root</code> el valor <code>false</code>.</p>
+
+``` /config/initializers/rabl_config.rb
+Rabl.configure do |config|
+ config.include_json_root = false
+end
+```
+
+<p>Como se ha modificado un inicializador tendremos que reiniciar la aplicaci&oacute;n para que estos cambios tengan efecto. Tras esto, veremos que el JSON del primer art&iacute;culo ya no incluir&aacute; el nodo ra&iacute;z.</p>
+
+``` terminal
+$ curl http://localhost:3000/articles/1.json
+{"id":1,"name":"Superman","published_at":"2012-01-19T18:38:50Z","edit_url":"http://localhost:3000/articles/1/edit","author":{"id":2,"name":"Clark Kent","url":"http://localhost:3000/authors/2"},"comments":[{"id":1,"name":"Lois Lane","content":"Does anyone know where I can find Superman?"},{"id":2,"name":"Lex Luthor","content":"I have some Kryptonite for you Superman!"}]}
+```
+
+<p>Se dan m&aacute;s detalles sobre las opciones de configuraci&oacute;n en la secci&oacute;n &quot;Configuration&quot; del <a href="https://github.com/nesquena/rabl/blob/master/README.md">README de RABL</a>. Hay otras funcionalidades que no hemos visto, como por ejemplo la serializaci&oacute;n a XML y <a href="http://msgpack.org/">Message Pack</a>.</p>
+
+<h3>C&oacute;mo embeber JSON en una p&aacute;gina web</h3>
+
+<p>A veces en lugar de llamar a una acci&oacute;n separada queremos incluir JSON directamente en un documento HTML. &iquest;C&oacute;mo podemos hacerlo con RABL? La plantilla HTML de la accion <code>index</code> tiene el siguiente aspecto:</p>
+
+``` /app/views/articles/index.html.erb
+<h1>Articles</h1>
+
+<div id="articles">
+<% @articles.each do |article| %>
+ <h2>
+ <%= link_to article.name, article %>
+ <span class="comments">(<%= pluralize(article.comments.size, 'comment') %>)</span>
+ </h2>
+ <div class="info">
+ by <%= article.author.name %>
+ on <%= article.published_at.strftime('%b %d, %Y') %>
+ </div>
+ <div class="content"><%= article.content %></div>
+<% end %>
+</div>
+```
+
+<p>A&ntilde;adiremos el JSON de los art&iacute;culos en un atributo <code>data-</code> del <code>div</code> contenedor. Podr&iacute;amos tambi&eacute;n invocar a <code>@articles.to_json</code> pero no estar&iacute;amos usando la plantilla RABL. En vez de esto podemos llamar a <code>render(:template)</code> y pasar el nombre de la plantilla.</p>
+
+``` /app/views/articles/index.html.erb
+<div id="articles" data-articles="<%= render(template: "articles/index.json.rabl") %>" >
+```
+
+<p>Si recargamos la p&aacute;gina y vemos el c&oacute;digo fuente veremos el JSON embebido.</p>
+
+``` html
+<div id="articles" data-articles="[{&quot;id&quot;:1,&quot;name&quot;:&quot;Superman&quot;,&quot;published_at&quot;:&quot;2012-01-19T18:38:50Z&quot;,&quot;edit_url&quot;:&quot;http://localhost:3000/articles/1/edit&quot;,&quot;author&quot;:{&quot;id&quot;:2,&quot;name&quot;:&quot;Clark Kent&quot;,&quot;url&quot;:&quot;http://localhost:3000/authors/2&quot;},&quot;comments&quot;:[{&quot;id&quot;:1,&quot;name&quot;:&quot;Lois Lane&quot;,&quot;content&quot;:&quot;Does anyone know where I can find Superman?&quot;},{&quot;id&quot;:2,&quot;name&quot;:&quot;Lex Luthor&quot;,&quot;content&quot;:&quot;I have some Kryptonite for you Superman!&quot;}]},{&quot;id&quot;:2,&quot;name&quot;:&quot;Krypton&quot;,&quot;published_at&quot;:&quot;2012-01-05T18:38:50Z&quot;,&quot;edit_url&quot;:&quot;http://localhost:3000/articles/2/edit&quot;,&quot;author&quot;:{&quot;id&quot;:2,&quot;name&quot;:&quot;Clark Kent&quot;,&quot;url&quot;:&quot;http://localhost:3000/authors/2&quot;},&quot;&quot;:[]},{&quot;id&quot;:3,&quot;name&quot;:&quot;Batman &amp; Robin&quot;,&quot;published_at&quot;:&quot;2012-01-26T18:38:50Z&quot;,&quot;edit_url&quot;:&quot;http://localhost:3000/articles/3/edit&quot;,&quot;author&quot;:{&quot;id&quot;:1,&quot;name&quot;:&quot;Bruce Wayne&quot;,&quot;url&quot;:&quot;http://localhost:3000/authors/1&quot;},&quot;comments&quot;:[{&quot;id&quot;:3,&quot;name&quot;:&quot;The Joker&quot;,&quot;content&quot;:&quot;Haha, Batman, you will see your bat signal tonight!&quot;},{&quot;id&quot;:4,&quot;name&quot;:&quot;Robin&quot;,&quot;content&quot;:&quot;Enough with the games Joker.&quot;},{&quot;id&quot;:5,&quot;name&quot;:&quot;Riddler&quot;,&quot;content&quot;:&quot;Did someone say games?&quot;}]}]" >
+```
+
+<p>Debemos tener en cuenta si utilizamos esta t&eacute;cnica que las variables de instancia que se utilicen en la plantilla deben ser establecidas desde la acci&oacute;n del controlador.</p>
Please sign in to comment.
Something went wrong with that request. Please try again.