<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
<channel>
<title>in web we trust</title>
<link>http://www.inwebwetrust.net</link>
<description>también en color en: &lt;a href="http://blat.lacoctelera.com"&gt;blat.lacoctelera.com&lt;/a&gt;</description>
<language>es-es</language>



<image>
	<url>http://a1.lacoctelera.com/myfiles/inwebwetrust/pies65x65.jpg</url>
	<title>in web we trust</title>
	<link>http://www.inwebwetrust.net</link>
</image>
<generator>the-shaker v0.1. More on http://www.the-shaker.com</generator>


<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/InWebWeTrust" type="application/rss+xml" /><item>
<title>Comprobar si una relacíon contiene un elemento</title>
<link>http://www.inwebwetrust.net/post/2008/06/09/comprobar-si-relacion-esta-vacia</link>
<pubDate>2008-06-09T18:28:04+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<category domain="http://www.inwebwetrust.net">Snippets y Trucos</category>
<content:encoded><![CDATA[<p>Muchas veces cuando trabajamos con ActiveRecord nos olvidamos / ignoramos qué hace por debajo.</p>
<p>Un claro ejemplo lo encontramos cuando tenemos una relación <code>:has_many</code> y queremos comprobar si un elemento está incluída en dicha relación.</p>
<p>Por ejemplo:</p>
<pre><code class="ruby">
class Place < ActiveRecord::Base
  has_many :items
end
</code></pre>
<pre><code class="ruby">
class Item < ActiveRecord::Base
  belongs_to :place
end
</code></pre>
<p>Seguro que más de una vez, para comprobar que un <em>place</em> contiene un <em>ítem</em> hemos utilizado el "rubysta" <code>include?</code>:</p>
<pre><code class="ruby">
place.items.include?(item)
</code></pre>
<p>Pensándolo fríamente 0.2 segundos nos damos cuenta de que estamos cargando un array con todos los elementos de una relación, que pueden ser 10 o pueden ser 1.000.000. Y ya sabemos lo generoso que es Ruby con la memoria que toma y que nunca deja ir.</p>
<p>Un truco para evitar que esto suceda sin dejar de utilizar <code>include?</code> es definir dicho método dentro de la relación tal que así:</p>
<pre><code class="ruby">
class Place < ActiveRecord::Base
  has_many :items do 
    def include?(item)
      count(:conditions => ["item_id = ?", item.id]) > 0
    end
  end
end
</code></pre>
<p>Es decir, resolvemos el problema con un simple <code>COUNT</code> de Mysql.</p>
<p>¿Alguien se anima a hacer un plugin? Creo que sería bastante inmediato para cuando se cumplen las convenciones y sabemos que la clave foránea de la relación es <em>singular del nombre de la relación</em>_id. O quizá ni eso, si encontramos la forma de preguntarle a ActiveRecord cuál es la clave foránea de una relación.</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2008/06/09/comprobar-si-relacion-esta-vacia#comentarios
</comments>
</item>

<item>
<title>Visualizar en el log de producción las querys lentas</title>
<link>http://www.inwebwetrust.net/post/2008/06/05/visualizar-el-log-produccion-querys-lentas</link>
<pubDate>2008-06-05T11:57:42+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<category domain="http://www.inwebwetrust.net">Snippets y Trucos</category>
<content:encoded><![CDATA[<p>Cuando tienes una aplicación en producción es más que necesario controlar los tiempos de las peticiones más lentas.</p>
<p>Sin embargo muchas veces con el log de Rails no es suficiente, y hay que alcanzar un mayor nivel de detalle.</p>
<p>El log en modo <code>debug</code> nos da todo el detalle que necesitamos, pero mostrando demasiada información (¿de qué nos sirve saber que un <code>SELECT</code> sencillo tarda 0.001 segundos?).</p>
<p>Pero si en ese log pudiéramos filtrar las consultas SQL más lentas sí que tendríamos información de consultas lentas asociadas a cada petición al servidor.</p>
<p>Gracias al plugin <a href="http://github.com/ntalbott/query_trace/tree/master">query trace</a> y a una pequeña modificación podemos mostrar qué consultas tardan más de 1 segundo:</p>
<p><code class="rub">
<pre>
module ActiveRecord
  module ConnectionAdapters
    class AbstractAdapter</p>
<p>      def log_info(sql, name, runtime)
        return unless @logger</p>
<p>        @logger.info(
          format_log_entry(
            "#{name.nil? ? "SQL" : name} (#{sprintf("%f", runtime)})",
            sql.gsub(/ +/, " ")
          )
        ) if (RAILS_ENV == 'production' && runtime > 1.0) || RAILS_ENV != 'production'
      end
    end
  end
end
</pre>
<p></code></p>
<p>Este código lo he probado en Rails 1.2.x, no sé si funcionará en otras versiones.
</p>
</p>]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2008/06/05/visualizar-el-log-produccion-querys-lentas#comentarios
</comments>
</item>

<item>
<title>Diferencias colorizadas en SVN y GIT</title>
<link>http://www.inwebwetrust.net/post/2008/05/31/diferencias-colorizadas-svn-y-git</link>
<pubDate>2008-05-31T06:31:57+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Snippets y Trucos</category>
<content:encoded><![CDATA[<p>Si trabajáis con control de versiones una de las operaciones más habituales es ver las modificaciones de un fichero. Eso en Subversion se hace con <code>svn diff</code>. </p>
<p>Sin embargo yo utilizo un script que creo que me pasó <a href="http://www.lacoctelera.com/porras">porras</a> para que me muestre en colores las modificaciones.</p>
<p>El script es este:</p>
<pre><code class="ruby">
#!/usr/bin/env ruby</p>
<p>`svn diff #{ARGV.join(' ')}`.each do |line|
  puts( if line =~ /^\+(.*)$/
        "\e[32m#{$&}\e[0m"
        elsif line =~ /^-(.*)$/
          "\e[31m#{$&}\e[0m"
        else
          line
        end
      )
end
</code></pre>
<p>Con darle permisos de ejecución ya podéis tener un <code>svndiff</code> por ejemplo.</p>
<p>No pongo el equivalente en git porque es bastante inmediato.
</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2008/05/31/diferencias-colorizadas-svn-y-git#comentarios
</comments>
</item>

<item>
<title>Límites en claves y valores de Memcached</title>
<link>http://www.inwebwetrust.net/post/2008/02/24/limites-claves-y-valores-memcached</link>
<pubDate>2008-02-24T12:13:14+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<content:encoded><![CDATA[<p>Una cuestión que hay que tener presente a la hora de trabajar con Memcached y que no se suele tener en cuenta es el tamaño de las claves y los valores:</p>
<ul>
<li><strong>claves</strong>: máximo de 250 caracteres</li>
<li><strong>valores alojados</strong>: máximo 1 Megabyte</li>
</ul>
<p>Es muy difícil que una aplicación Rails las claves generadas a partir de las URL's tengan tanto tamaño, pero puede darse el caso y hay que tenerlo presente.</p>
<p>En el grupo de discusión <a href="http://groups.google.com/group/acts_as_cached?hl=en">acts_as_cached</a> esta semana han propuesto <em>hashear</em> (con MD5, por ejemplo) las claves antes de guardarlas para curarnos en salud.</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2008/02/24/limites-claves-y-valores-memcached#comentarios
</comments>
</item>

<item>
<title>Sirviendo feeds cacheados con Nginx directamente</title>
<link>http://www.inwebwetrust.net/post/2008/01/16/sirviendo-feeds-cacheados-con-nginx-directamente</link>
<pubDate>2008-01-16T00:02:58+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Snippets y Trucos</category>
<content:encoded><![CDATA[<p>Reconozco que me ha constado dios y ayuda dar con la regla adecuada, así que por eso me he decidido a postearla.</p>
<p>El problema es el siguiente: en <a href="http://unvlog.com">unvlog.com</a> (sí, ese proyecto del que no he hablado) somos muy Rails y tenemos para todos los recursos que tiene sentido una ruta que responde a un formato u otro según se le solicite pero con esta forma:</p>
<p>En concreto, esta URL corresponde al feed de un blog, feed que está cacheado en disco gracias a la <strong>caché de página</strong> de Rails. Pues bien, la idea es que el servidor web sirva directamente esta caché, así que una regla podría ser:</p>
<pre><code>
  if (-f /cache/$request_filename) {
          rewrite (.*) /cache/$1 break;
  }
</code></pre>
<p>(Esto, asumiendo que tenemos la caché en <strong><code>public/cache</code></strong>)</p>
<p>El problema es que esta regla no funciona, y creo que se debe a que <strong>blat.atom</strong> lleva un '.' y no es capaz de asignar la URL a la variable <code>$request_filename</code>.</p>
<p>Al final ha sido tan fácil como utilizar otra variable que he encontrado en la parte rusa del wiki, <code>$request_uri</code>:</p>
<pre><code>
  if (-f $document_root/cache/$request_uri) {
          rewrite ^/(.*).atom$ /cache/$1.atom break;
  }
</code></pre>
<p>Con esto ha funcionado perfectamente y ya tenemos cacheados y servidos por Nginx los feeds en <a href="http://unvlog.com">unvlog.com</a>.</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2008/01/16/sirviendo-feeds-cacheados-con-nginx-directamente#comentarios
</comments>
</item>

<item>
<title>Comprendiendo las estadísticas del Memcached</title>
<link>http://www.inwebwetrust.net/post/2008/01/15/comprendiendo-estadaasticas-del-memcached</link>
<pubDate>2008-01-15T22:30:50+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby</category>
<content:encoded><![CDATA[<p><a href="http://www.danga.com/memcached/">Memcached</a> (o Memcache) incorpora un sistema de estadísticas interno que nos permite conocer el estado del demonio, su capacidad restante de almacenamiento, uso, conextiones, etcétera.</p>
<p>Para acceder a él a través del cliente de Ruby, por ejemplo, basta con cargar una consola en el entorno deseado e invocar al método <code class="ruby">stats</code> del objeto de caché.</p>
<p>Por ejemplo, si nuestra configuración es la siguiente:</p>
<pre><code class="ruby">
  CACHE = MemCache.new 'localhost:11211', :namespace => 'wadus_fragments'
</code></pre>
<p>Podemos utilizar el objeto <code>CACHE</code> de la siguiente manera:</p>
<pre><code class="ruby">
  pp CACHE.stats
  {"bytes"=>746532339,
   "pid"=>10303,
   "connection_structures"=>19,
   "time"=>1200349556,
   "limit_maxbytes"=>1073741824,
   "cmd_get"=>689486,
   "version"=>"1.1.12",
   "bytes_written"=>3296488315,
   "cmd_set"=>265986,
   "get_misses"=>265168,
   "total_connections"=>1238,
   "curr_connections"=>17,
   "curr_items"=>66977,
   "uptime"=>56490,
   "get_hits"=>424318,
   "total_items"=>265986,
   "rusage_system"=>95.012555,
   "rusage_user"=>17.16339,
   "bytes_read"=>3226552602}
</code></pre>
<p>La interpretación de todos estos valores se puede encontrar en <a href="http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt">la definición del protocolo</a>:</p>
<pre>
  Name              Type     Meaning
  ----------------------------------
  pid               32u      Process id of this server process
  uptime            32u      Number of seconds this server has been running
  time              32u      current UNIX time according to the server
  version           string   Version string of this server
  pointer_size      32       Default size of pointers on the host OS
                             (generally 32 or 64)
  rusage_user       32u:32u  Accumulated user time for this process 
                             (seconds:microseconds)
  rusage_system     32u:32u  Accumulated system time for this process 
                             (seconds:microseconds)
  curr_items        32u      Current number of items stored by the server
  total_items       32u      Total number of items stored by this server 
                             ever since it started
  bytes             64u      Current number of bytes used by this server 
                             to store items
  curr_connections  32u      Number of open connections
  total_connections 32u      Total number of connections opened since 
                             the server started running
  connection_structures 32u  Number of connection structures allocated 
                             by the server
  cmd_get           64u      Cumulative number of retrieval requests
  cmd_set           64u      Cumulative number of storage requests
  get_hits          64u      Number of keys that have been requested and 
                             found present
  get_misses        64u      Number of items that have been requested 
                             and not found
  evictions         64u      Number of valid items removed from cache                                                                           
                             to free memory for new items                                                                                       
  bytes_read        64u      Total number of bytes read by this server 
                             from network
  bytes_written     64u      Total number of bytes sent by this server to 
                             network
  limit_maxbytes    32u      Number of bytes this server is allowed to
                             use for storage. 
  threads           32u      Number of worker threads requested.
                             (see doc/threads.txt)
</pre>
<p>En concreto cuatro parámetros me han parecido interesantes de observar:</p>
<ul>
<li>el parámetro <strong><code>bytes</code></strong> junto con el de <strong><code>limit_maxbytes</code></strong>: el primero representa el total de bytes ocupados actualmente, frente el máximo. </li>
<li>el número de fallos de caché que refleja el valor del parámetro <strong><code>get_misses</code></strong> junto con el número de aciertos <strong><code>get_hits</code></strong></li>
</ul>
<p>Los primeros nos permiten saber si hemos llegado al límite el almacenamiento que necesita nuestra aplicación y el segundo nos permite saber si nuestra política de caché es adecuada: diviendo <em>hits</em> entre <em>misses</em> obtenemos la proporción de fragmentos encontrados frente a fragmentos que ya no existían. Un valor de 1 indica que por cada dos búsquedas, una tiene éxito y otra no.</p>
<p>Por supuesto un valor inferior a uno muestra que la caché no sirve de nada (indicaría por ejemplo que necesitaríamos ampliar el Memcache o que tenemos una política de borrado "exagerada").</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2008/01/15/comprendiendo-estadaasticas-del-memcached#comentarios
</comments>
</item>

<item>
<title>Caché en Rails</title>
<link>http://www.inwebwetrust.net/post/2007/11/30/cachao-rails</link>
<pubDate>2007-11-30T14:25:33+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<category domain="http://www.inwebwetrust.net">Charlas y Presentaciones</category>
<content:encoded><![CDATA[<p>Rompo este silencio para subir una de mis charlas de la <a href="http://conferenciarails.org/" title="http://conferenciarails.org/" id=link_0>Conferencia Rails</a> :</p>
<p><a href="http://www.inwebwetrust.net/myfiles/inwebwetrust/cache.pdf">Caché en Rails</a></p>
<p>Pronto, todas las demás, colgadas en la web de la Conferencia,</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/11/30/cachao-rails#comentarios
</comments>
</item>

<item>
<title>Un pequeña benchmark sobre servidores web + aplicación con Rails y Merb</title>
<link>http://www.inwebwetrust.net/post/2007/09/03/un-pequena-benchmark-sobre-servidores-web-aplicacion-con-rails</link>
<pubDate>2007-09-03T08:57:01+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<content:encoded><![CDATA[<p><a href="http://www.webficient.com/2007/08/testing-various-configurations-of-rails.html">Testing Various Configurations of Rails, Merb, Swiftiply, and Nginx</a> es una más que interesante comparativa entre el clásico Mongrel y una alternativa que ha surgido hace poco <a href="http://swiftiply.swiftcore.org/">Swiftiply</a>: un servidor <em>proxy</em> que además, nos regala una variante de Mongrel, el <em>evented Mongrel</em>, totalmente compatible, pero que basa su funcionamiento en gestión de eventos (<a href="http://rubyforge.org/projects/eventmachine">EventMachine</a>), en lugar de utilizar los clásicos <em>threads</em>.</p>
<p>Además, en el post utilizan <a href="http://wiki.codemongers.com/Main">Nginx</a> como servidor web y <a href="http://www.rubyonrails.org/">Ruby on Rails</a> y <a href="http://merb.rubyforge.org/">Merb</a>, como frameworks de desarrollo, así como Memcached para almacenar sesiones.</p>
<p>Los resultados, muy interesantes:</p>
<ul>
<li>Merb es mucho más rápido que Rails, a costa de perder parte de la magia</li>
<li>Nginx es una gran alternativa a Apache, sobretodo cuando la memoria es un recurso escaso (en mi nuevo <a href="http://www.slicehost.com/">Slicehost</a>, por ejemplo)</li>
<li>y, el más importante, el <em>evented Mongrel</em> funciona bastante mejor que el Mongrel en situaciones de alta concurrencia</li>
</ul>
<p>Así que si te gusta "jugar" y quieres probarlo, lo recomiendo: la instalación es muy sencilla y los resultados saltan a la vista.</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/09/03/un-pequena-benchmark-sobre-servidores-web-aplicacion-con-rails#comentarios
</comments>
</item>

<item>
<title>Sobre httperf y las pruebas de carga</title>
<link>http://www.inwebwetrust.net/post/2007/08/18/sobre-httperf-y-pruebas-carga</link>
<pubDate>2007-08-18T20:17:05+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<category domain="http://www.inwebwetrust.net">Desarrollo Web</category>
<content:encoded><![CDATA[<p>Andaba yo viendo esta mañana el <em>screencast</em> de Peepcode <a href="http://peepcode.com/products/benchmarking-with-httperf">Benchmarking with httperf</a> bastante emocionado (ya que la fama precede a estos <em>screencasts</em>) para ver cómo podía mejorar las pruebas de rendimiento que estoy haciendo contra una aplicación Rails que he instalado en mi recién adquirido Slicehost.</p>
<p>La situación es la siguiente: es una cuenta <a href="http://www.slicehost.com/">Slicehost</a> de 256<abbr title="Megabytes">Mb</abbr> de memoria, en el que tú instalas lo que quieres. El problema es que debes de instalar un servidor web, los servidores de aplicaciones y la base de datos, y todos ellos han de luchar por esos 256Mb. Así que al final me he decidido por instalar esto:</p>
<ul>
<li><strong>servidor web</strong>: Nginx, que tenía ganas de probarlo tras leer a uno de los <em>sysadmins</em> decir que Nginx era lo más estable que había visto nunca, y que recomendaba usar Apache sólo en el caso de querer que un mismo servidor web compartiera diferentes aplicaciones y en distintos lenguajes (PHP y Rails, por ejemplo). Además, su uso de memoria es ridículo.</li>
<li><strong>servidor de aplicaciones</strong>: Mongrel. Considerando los 60Mb que viene a consumir un Mongrel de memoria, el número de Mongrels en el clúster lo he establecido a 3.</li>
<li><strong>servidor de base de datos</strong>: MySQL. No había otra opción.</li>
</ul>
<p>Además de todo esto, hay un servidor Memcached de 32Mb para guardar las sesiones.</p>
<p>Y claro, quería hacer pruebas de carga contra el stack completo para ver de rendimiento qué tal.</p>
<p>Las pruebas se han realizado contra una página sin caché y con bastantes consultas a la base de datos, cuyo tiempo de respuesta medio es de 0.005 segundos o lo que es lo mismo, unas 20 <abbr title="peticiones por segundo">req/s</abbr>.</p>
<h3>El screencast</h3>
<p>El <em>screencast</em> se queda algo corto en cuanto a uso de la herramienta <a href="http://www.hpl.hp.com/research/linux/httperf/">httperf</a>, ya que el autor pierde mucho tiempo explicando conceptos teóricos y muy básicos de Estadística: <a href="http://es.wikipedia.org/wiki/Promedio">media</a> y <a href="http://es.wikipedia.org/wiki/Desviaci%C3%B3n_est%C3%A1ndar">desviación estándar</a>, así como cómo mostrar luego los resultados a través de gráficas (unas muy bonitas generadas con <a href="http://nubyonrails.com/pages/gruff">gruff</a>).</p>
<p>Posteriormente las pruebas las realiza contra un único Mongrel, explicando con todo detalle:</p>
<ul>
<li>la importancia de utilizar datos reales: la muestra debe de ser representativa para que los resultados lo sean</li>
<li>la importancia de obtener muchas muestras: cuantas más muestras, la media y la varianza son más significativas también</li>
<li>la importancia de anotar todos los resultados</li>
<li>la importancia de la interpretación de los mismos en función de los resultados obtenidos y entender qué significan</li>
</ul>
<p>Las pruebas las realiza para comparar el rendimiento de su aplicación sin usar caché, utilizando caché de acción y utilizando caché de página. Así que establece el <em>baseline</em> en los resultados obtenidos sin utilizar caché y a partir de los obtenidos utilizando caché establece porcentajes de mejora.</p>
<h3>Otros aspectos a tener en cuenta</h3>
<p>Hay otras muchas situaciones en las que es recomendable hacer pruebas de rendimiento contra tu propia aplicación:</p>
<ul>
<li>calcular el número de Mongrels a lanzar en el servidor de aplicaciones. Una buena explicación (aunque breve también), la da Zed en la página de Mongrel: <a href="http://mongrel.rubyforge.org/docs/how_many_mongrels.html">How many Mongrels</a></li>
<li>comparar el rendimiento entre distintos sistemas de almacenamiento de sesiones</li>
<li>comparar distintos algoritmos de balanceo en el módulo de proxy</li>
<li>determinar el tope máximo de ficheros servidos a través de una unidad NFS</li>
<li>...</li>
</ul>
<p>En estos casos es posible que nos interese conocer algún parámetro más de <code>httperf</code> que los que se han explicado en el vídeo:</p>
<ul>
<li><code>--rate</code>: determinar el número de peticiones concurrentes lanzadas en un segundo</li>
<li><code>--wsess</code>: determina cada cuántas peticiones se inicia una nueva sesión</li>
</ul>
<p>Y además, si vais a hacer pruebas de carga, hay que tener en cuenta estas perogrulladas, que a veces no lo son tanto:</p>
<ol>
<li>el número de Mongrels en el clúster</li>
<li>la conexión: ¡no hagas las pruebas con un ADSL! En mi caso he pasado de 30 req/s a más de 50 req/s sólo por lanzar las pruebas desde una máquina con una conexión decente</li>
<li>testea el <em>stack</em> entero: sobre todo porque es interesante ver si hay problemas de conectividad entre una capa (web) y la otra (aplicación), o si el proxy que reparte la carga está mal configurado, etcétera</li>
</ol>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/08/18/sobre-httperf-y-pruebas-carga#comentarios
</comments>
</item>

<item>
<title>Trabajando con BackgroundDRB en el entorno de test</title>
<link>http://www.inwebwetrust.net/post/2007/08/13/trabajando-con-backgrounddrb-el-entorno-test</link>
<pubDate>2007-08-13T12:06:26+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<category domain="http://www.inwebwetrust.net">Testing</category>
<content:encoded><![CDATA[<p><a href="http://backgroundrb.devjavu.com/">BackgrounDRB</a> es un proyecto en desarrollo que pretende crear un servicio estable para ejecutar tareas en segundo plano, sin que estas entorpezcan la navegación del usuario por la aplicación, relentizando sus tiempos de respuesta.</p>
<p>La verdad es que era un completo desconocido para mí hasta que encontré la presentación de <a href="http://spejman.blogspot.com/">Sergio Espeja</a> en la conferencia de Rails: <a href="http://bee.com.es/espeja/conferenciarails">Tareas en background con RoR y BackgrounDRb</a>.</p>
<p>En este año que ha pasado, hay una <a href="http://backgroundrb.devjavu.com/projects/backgroundrb/browser/trunk" title="http://backgroundrb.devjavu.com/projects/backgroundrb/browser/trunk" id=link_0>nueva versión</a> que corrige algunos fallos y deja otros abiertos, pero que es, dicen, bastante estable. Y la verdad es que con la anterior tuve muchos problemas para crear mis <em>workers</em> pero con esta estoy encantado.</p>
<p>Pero este post no era para hablar de las bondades del proyecto, que son muchas, sino para contar cómo hacer que en los <em>tests</em> no necesitemos tener lanzado un servidor BackgroundDRB para que estos funcionen, sino que podemos utilizar un <strong>mock</strong>.</p>
<p>He encontrado uno <a href="http://backgroundrb.devjavu.com/projects/backgroundrb/ticket/54">entre los tickets del proyecto</a>, y que se ve que aún no está incluído en la última versión.</p>
<p>Basta con descargarlo en <code>test/mocks/test</code> e incluir la siguiente línea en el <code>test_helper.rb</code>:</p>
<pre><code class="ruby">
require File.dirname(__FILE__) + '/mocks/test/backgroundrb_mock.rb'
</code></pre>
<p>Y voilá, tests funcionando de nuevo.
</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/08/13/trabajando-con-backgrounddrb-el-entorno-test#comentarios
</comments>
</item>

<item>
<title>Testeando helpers</title>
<link>http://www.inwebwetrust.net/post/2007/08/12/testeando-helpers</link>
<pubDate>2007-08-12T11:35:15+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<category domain="http://www.inwebwetrust.net">Testing</category>
<category domain="http://www.inwebwetrust.net">Snippets y Trucos</category>
<content:encoded><![CDATA[<p>El otro día, buscando información sobre cómo testear <em>helpers</em> en Rails di con este post: <a href="http://nubyonrails.com/articles/2006/04/07/test-your-helpers">Test your helpers</a>, en el que el autor habla de un <em>plugin</em> desarrollado por él mismo que facilita sobremanera la labor.</p>
<p>El <em>plugin</em> se llama <a href="http://topfunky.net/svn/plugins/helper_test/">helper_test</a> y es muy sencillo de utilizar:</p>
<ol>
<li>descargar</li>
<li>editar <code>tests/test_helper.rb</code> e incluír la línea: <code>require File.expand_path(File.dirname(__FILE__) + '/helper_testcase')</code></li>
<li>utilizar el generador que incluye: <code>./script/generate helper_test Foo</code></li>
</ol>
<p>El test generado tendrá este aspecto:</p>
<pre><code class="ruby">
  require File.dirname(__FILE__) + '/../../test_helper'
</code><code class="ruby">
  class FooHelperTest < HelperTestCase
</code><code class="ruby">
    include FooHelper
</code><code class="ruby">
    #fixtures :users, :articles
</code><code class="ruby">
    def setup
      super
    end
</code><code class="ruby">
  end
</code></pre>
<p>A destacar que podemos utilizar <em>fixtures</em>.</p>
<p>Y la forma de proceder también es muy sencilla: creamos un test y en su interior podemos invocar al <em>helper</em> como si de un método más se tratara y comparar el resultado obtenido con los valores esperados. Si el <em>helper</em> tiene argumentos, ampliaremos el abanico de pruebas.</p>
<h3>Una pequeña reflexión</h3>
<p>La verdad es que no he podido pensar mucho sobre la efectividad de este <em>plugin</em> ni tampoco tengo experiencia utilizándolo (de hecho los desarrolladores de The-Shaker estábamos algo preocupados sobre el vacío que teníamos en los <em>helpers</em> de la aplicación, pues no tienen tests). En principio y echando un pequeño vistazo a los <em>helpers</em> que tenemos, parece que sí que se van a poder testear todos utilizando este <em>plugin</em>.</p>
<p>Sin embargo, hay que notar dos cosas:</p>
<p>La primera es que si en tu <em>helper</em> has utilizado una variable de instancia (confiando en que en la vista donde vas a utilizar dicho <em>helper</em>, la variable ya esté instanciada y con valor), debes de asignar una variable de igual nombre antes de invocar al helper en el test. Por ejemplo:</p>
<pre><code class="ruby">
def available_tabs
  tabs =  "&lt;ul&gt;\n"
  tabs << " &lt;li id=\"tab_blog\"&gt;" + link_to(_("Blog"), :controller =&gt; 'posts',
           :action =&gt; 'index', :blog_nicetitle =&gt; @blog.nicetitle) + "&lt;/li&gt;\n"
  tabs << "&lt;/ul&gt;\n"
end</code></pre>
<p>Y el test:</p>
<pre><code class="ruby">
def test_avaible_tabs
  @blog = blogs(:el_blog_de_quentin)
  tabs = available_tabs
  assert_equal tabs, '....'
end</code></pre>
<p>Y la segunda es más bien una sugerencia: muchas veces los <em>helpers</em> generan HTML, y todos sabemos lo coñazo que puede ser comprobar la estructura del mismo, y las bondades del <a href="http://api.rubyonrails.com/classes/ActionController/Assertions/SelectorAssertions.html#M000208"><code>assert_select</code></a>. Pues bien, se puede hacer un <em>hack</em> no muy elegante, pero bastante práctico para poder utilizar <code>assert_select</code> con el valor obtenido por un <em>helper</em>. Basta con editar el fichero <code>helper_testcase.rb</code> e incluír la línea:</p>
<pre><code class="ruby">
  @response   = ActionController::TestResponse.new
</code></pre>
<p>dentro de la función <code>setup</code>. Y ahora, con que asignemos el <em>helper</em> a <code>@response.body</code> ya lo tenemos. Veamos un ejemplo:</p>
<pre><code class="ruby">
def test_avaible_tabs
  @blog = blogs(:el_blog_de_quentin)
  @response.body = available_tabs
  assert_select 'ul'
end</code></pre>
<p>Es sucio, poco semántico, y muy <abbr title="¿aún no sabes qué es esto?">DRY</abbr>, porque lo tienes que asignar tras cada invocación al <em>helper</em>, pero parece que de momento no hay otra forma. ¿Alguien se atreve a redefinir?
</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/08/12/testeando-helpers#comentarios
</comments>
</item>

<item>
<title>Tests de unidad de ActionMailer</title>
<link>http://www.inwebwetrust.net/post/2007/08/12/tests-unidad-actionmailer</link>
<pubDate>2007-08-12T09:20:45+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<category domain="http://www.inwebwetrust.net">Testing</category>
<content:encoded><![CDATA[<p>ActionMailer es la librería incluída en Ruby on Rails para gestionar el envío de correos desde el framework.</p>
<p>Su <a href="http://wiki.rubyonrails.org/rails/pages/ActionMailer" title="http://wiki.rubyonrails.org/rails/pages/ActionMailer" id=link_0>uso</a> es bastante sencillo y cumple su labor perfectamente, a excepción de pequeños detalles que parece que falten por pulir.</p>
<p>Uno de esos "detalles insignificantes" es, para mi humilde opinión, el <em>testing</em>, que, aunque se puede realizar sin problemas, y con una cobertura muy buena de la funcionalidad, no queda tan limpio como queda en otras partes del <em>framework</em>.</p>
<p>De hecho, una de las cosas que más se echa en falta es algo de documentación. Por suerte, en los <a href="http://manuals.rubyonrails.com/">Manuales de Rails</a> (qué mal suena, ¿no?), encontramos un "libro" sobre <a href="http://manuals.rubyonrails.com/read/book/5">testing en Rails</a>, y uno de sus capítulos es <a href="http://manuals.rubyonrails.com/read/chapter/64">testing your Mailers</a>, que es justo lo que queremos hacer.</p>
<p>Ahí proponen un esquema o esqueleto para los tests de unidad tal que así:</p>
<pre><code class="ruby">
require File.dirname(__FILE__) + '/../test_helper'
require 'my_mailer'
</code>
<code class="ruby">
class MyMailerTest < Test::Unit::TestCase
  fixtures :users
  FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures'
  CHARSET = "utf-8" 
</code><code class="ruby">
  include ActionMailer::Quoting
</code><code class="ruby">
  def setup
    ActionMailer::Base.delivery_method = :test
    ActionMailer::Base.perform_deliveries = true
    ActionMailer::Base.deliveries = []
</code><code class="ruby">
    @expected = TMail::Mail.new
    @expected.set_content_type "text", "plain", { "charset" => CHARSET }
  end
</code><code class="ruby">
  def test_reset_password
    user = User.find(:first)
    newpass = 'newpass'
    response = MyMailer.create_reset_password(user,newpass)
    assert_equal 'Your New Password', response.subject
    assert_match /Dear #{user.full_name},/, response.body
    assert_match /New Password: #{newpass}/, response.body
    assert_equal user.email, response.to[0]
  end
</code><code class="ruby">
  private
    def read_fixture(action)
      IO.readlines("#{FIXTURES_PATH}/community_mailer/#{action}")
    end
</code><code class="ruby">
    def encode(subject)
      quoted_printable(subject, CHARSET)
    end
end
</code></pre>
<p>Así un poco por encima, además de los requires pertinentes y de establecer unas cuantas constantes debemos de incluír <code class="ruby">include ActionMailer::Quoting</code> para poder utilizarlo en los tests con aquellos <em>emails</em> que tengan acentos, eñes o cualquier otro carácter no estándar en el <em>subject</em>.</p>
<p>En el método <code>setup</code> configuramos el <code>ActionMailer</code> y además creamos un objeto <code>TMail</code> llamado <code class="ruby">@expected</code>, y que utilizaremos en todos los tests para compararlo con el que genera nuestro modelo:</p>
<pre><code class="ruby">
  def setup
    ActionMailer::Base.delivery_method = :test
    ActionMailer::Base.perform_deliveries = true
    ActionMailer::Base.deliveries = []
</code><code class="ruby">
    @expected = TMail::Mail.new
    @expected.set_content_type "text", "plain", { "charset" => CHARSET }
  end
</code></pre>
<p>Y respecto a las <em>fixturas</em>, básicamente no tenemos, así que nos proponen utilizar ficheros de texto plano cuyo contenido será el contenido del <em>email</em>. Esos ficheros se sitúan en <code>RAIlS_ROOT/test/fixtures/community_mailer/</code> como se puede ver en la función <code>read_fixture</code>:</p>
<pre><code class="ruby">
  def read_fixture(action)
    IO.readlines("#{FIXTURES_PATH}/community_mailer/#{action}")
  end
</code></pre>
<h4>Nuestro propio test</h4>
<p>Con el esquema ya creado podemos empezar a escribir nuestros propios tests sobre nuestros modelos de <code>Mailer</code>.</p>
<p>Por ejemplo, veamos una acción muy simple de <a href="http://www.lacoctelera.com">La Coctelera</a>, que te envía un <em>email</em> cada vez que alguien te añade como amigo:</p>
<pre><code class="ruby">
	def new_friend(user,friend)
    @headers['reply-to'] = user.email
    @from = 'admin@domain.com'
    @recipients = friend.email
    @subject = "[La Coctelera] #{user.shortname} te ha añadido como amigo"
    @body = {
      'user_name' => user.name,
      'friend_name' => friend.name,
      'profile_link' => profile_url(user.username),
      'profile_link_friends' => friends_url(friend.username)
    }
  end
</code></pre>
<p>Y esta es la vista asociada:</p>
<pre><code class="ruby">
Hola <%= @friend_name %>!
</code><code class="ruby">
<%= @user_name %> te ha añadido como amig@. Puedes visitar su página en la siguiente
dirección: <%= @profile_link %>
</code><code class="ruby">
Puedes ver a todos tus amigos en:
</code><code class="ruby">
<%= @profile_link_friends %>
</code><code class="ruby">
Hasta otra!
</code><code class="ruby">
--
La Coctelera
http://www.lacoctelera.com
</code></pre>
<p>El test podría ser algo tal que así:</p>
<pre><code class="ruby">
def test_new_friend
  user = User.find_by_username('lucas')
  friend = User.find_by_username('blat')
  @expected.from = APP['adminmaster']
  @expected.subject = encode("[La Coctelera] #{user.shortname} te ha añadido como amigo")
  @expected.body = read_fixture('new_friend')
  @expected.to = friend.email
  @expected.reply_to = user.email
  assert_equal @expected.encoded, Notifier.create_new_friend(user, friend).encoded
end
</code></pre>
<p>El procedimiento es muy sencillo:</p>
<ul>
<li>cargamos a los dos usuarios implicados en la acción</li>
<li>vamos rellenando los atributos de <code class="ruby">@expected</code> con los valores que esperamos que tenga el <em>email</em> resultante: remitente, asunto, contenido, destinatario...</li>
<li>finalmente, comparamos el <em>email</em> "esperado", con el que genera la acción <code>create_new_friend</code></li>
</ul>
<p>Hemos necesitado crear una <em>fixtura</em> <code>new_friend</code> con el siguiente contenido:</p>
<pre><code>
Hola Fernando!</p>
<p>Lucas Nicolás te ha añadido como amig@. Puedes visitar su página en la siguiente dirección: http://test.host/lucas/perfil</p>
<p>Puedes ver a todos tus amigos en:</p>
<p>http://test.host/blat/amigos</p>
<p>Hasta otra!</p>
<p>--
La Coctelera
http://test.host
</code></pre>
<p>Como veis, esta <em>fixtura</em> tiene una limitación más que evidente: no es dinámica, y su contenido depende de los valores (en este caso de los usuarios), que estamos utilizando en el test.</p>
<p>También quiero destacar esta línea:</p>
<pre><code class="ruby">
  @expected.subject = encode("[La Coctelera] #{user.shortname} te ha añadido como amigo")
</code></pre>
<p>Cuando el <em>subject</em> del email vaya a incluir algún caracter acentuado, o con eñe, como es el caso, hay que forzar la recodificación de la cadena, pues <code>ActionMailer</code> también la recodificará cuando cree el <em>email</em>.</p>
<p>En un post posterior propondremos un par de mejoras para solventar alguna de las deficiencias que hemos visto.</p>
</%=></%=></%=></%=>]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/08/12/tests-unidad-actionmailer#comentarios
</comments>
</item>

<item>
<title>Entendiendo la diferencia entre and y &amp;&amp;</title>
<link>http://www.inwebwetrust.net/post/2007/08/05/entendiendo-diferencia-entre-and-y-</link>
<pubDate>2007-08-05T22:43:11+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby</category>
<content:encoded><![CDATA[<p>Para aquellos que nos preguntábamos por qué <code>&amp;&amp;</code> y <code>and</code> no son lo mismo, y porqué en el <a href="http://dev.rubyonrails.org/">Core de Rails prefieren <code>&amp;&amp;</code></a> aquí hay <a href="http://blog.jayfields.com/2007/08/ruby-operator-precedence-of-and-which.html">una buena explicación sobre cuál es su principal diferencia</a>, que no es más que un tema de precedencia de operadores.</p>
<p>Supongo que todo es acostumbrarse a utilizar uno u otro.</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/08/05/entendiendo-diferencia-entre-and-y-#comentarios
</comments>
</item>

<item>
<title>Y antes fue la línea de comandos...</title>
<link>http://www.inwebwetrust.net/post/2007/07/30/y-antes-fue-linea-comandos-</link>
<pubDate>2007-07-30T23:45:02+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Snippets y Trucos</category>
<content:encoded><![CDATA[<p>La línea de comandos (¿esa gran desconocida?), es una de las mejores herramientas que tenemos a mano los que desarrollamos en entorno UNIX/Linux. Por eso, <a href="http://railstips.org/2007/7/30/i-can-has-command-line">posts como este</a>, inspiran.</p>
<p>Y es que seguro que no todo lo que cuenta lo desconoces, pero tiene dos o tres perlas muy buenas. </p>
<p>Aquí van las que más me han gustado:</p>
<p><strong>Repetir un comando con sudo</strong>:</p>
<pre><code>
	$ vim /etc/hosts
	$ sudo !!
	sudo vim /etc/hosts
	Password:
</code></pre>
<p><strong>Utilizar el <code>history</code> para lanzar comandos</strong>:</p>
<pre><code>
$ history | head
    6  vim config/deploy.rb 
    7  vim config/deploy
    8  vim config/deploy.rb 
    9  cap club_deploy
   10  ssh bellini
   11  cd Proyectos/new-shaker-club/
   12  vim appserver/etc/logrotate.d/the-shaker
$ !10 # lanza un ssh a bellini
</code></pre>
<p><strong>Alias de irb</strong>:</p>
<pre><code>
	alias irb='irb --readline -r irb/completion -rubygems' # use readline, completion and require rubygems by default for irb
</code></pre>
<p>Hay muchísimos más en el post que vale la pena repasar.</p>
<p>Y aquí algunos de mi cosecha:</p>
<p><strong>Alias para resetear caché de resolución de nombres</strong> (ideal para cuando modificas el <code>/etc/hosts</code>):</p>
<pre><code>
	alias dns='sudo lookupd -flushcache'
</code></pre>
<p><strong>Alias para ver los cambios en Subversion del directorio actual</strong>:</p>
<pre><code>
	alias stm='svn st | grep ^M'
</code></pre>
<p>Seguro que tú también utilizas alguno que otro, ¡así que ahí tienes los comentarios para compartirlo con los demás!</p>
<p><strong>Actualización</strong>: y como remate a este post os dejo mi <code>.irbrc</code> en <a href="http://pastie.caboo.se/85037">este pastie</a>.
</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/07/30/y-antes-fue-linea-comandos-#comentarios
</comments>
</item>

<item>
<title>Ofertas de empleo en The Cocktail: administrador de sistemas y programador</title>
<link>http://www.inwebwetrust.net/post/2007/07/23/ofertas-empleo-the-cocktail-administrador-sistemas-y</link>
<pubDate>2007-07-23T06:42:53+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">The Cocktail</category>
<content:encoded><![CDATA[<p>Desempolvo el blog para informar que en <a href="http://www.the-cocktail.com">The Cocktail</a> buscamos un <strong>administrador de sistemas</strong> y un <strong>programador</strong>.</p>
<p>Podéis leer la oferta entera <a href="http://the-cocktail.com/empleo.html">en nuestra página de empleo</a>.</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/07/23/ofertas-empleo-the-cocktail-administrador-sistemas-y#comentarios
</comments>
</item>

<item>
<title>Google lee tus e-mails</title>
<link>http://www.inwebwetrust.net/post/2007/06/22/google-lee-tus-e-mails</link>
<pubDate>2007-06-22T11:27:45+00:00</pubDate>
<content:encoded><![CDATA[<p>Que Google lee tus e-mails es un hecho por todos conocido, y cuyo fin, sea cual sea, de momento sólo se ve reflejado en la publicidad que se muestra a la derecha.</p>
<p>Sin embargo hoy me ha sorprendido encontrar esto:</p>
<p><img src='http://www.inwebwetrust.net/myfiles/inwebwetrust/gmail-contextual.png' id='img_0' height='320' width='228' align='middle'/></p>
<p>Interesante forma de integrar servicios, sobre todo el de mapas.
</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/06/22/google-lee-tus-e-mails#comentarios
</comments>
</item>

<item>
<title>Cosas que hago al empezar un nuevo proyecto en Rails</title>
<link>http://www.inwebwetrust.net/post/2007/06/09/cosas-hago-al-empezar-nuevo-proyecto-rails</link>
<pubDate>2007-06-09T16:03:19+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<category domain="http://www.inwebwetrust.net">Snippets y Trucos</category>
<content:encoded><![CDATA[<p>A lo largo de todo este tiempo que llevo como desarrollador de Rails he cogido una serie de manías y hábitos, a la vez que he descubierto una serie de herramientas y <em>plugins</em> que me han parecido imprescindibles, y que incluso podrían venir incorporadas de serie en Rails.</p>
<p>Así que tras el clásico <code class="ruby">rails vaporware_project</code> hago lo siguiente:</p>
<h3>Instalar el plugin annotate_models</h3>
<p>Se trata de un plugin que te copia un listado de atributos de la clase como comentarios en los ficheros del modelo y de las <em>fixturas</em> mediante un simple <code class="ruby">rake annotate_models</code>.</p>
<p>El resultado es algo como esto:</p>
<pre><code class="ruby">
# == Schema Information
# Schema version: 4
#
# Table name: sources
#
#  id          :integer(11)   not null, primary key
#  url         :string(255)   default(), not null
#  feed_type   :string(255)   default(), not null
#  title       :string(255)   default(), not null
#  description :text          
#  created_at  :datetime      not null
#  updated_at  :datetime      not null
#
class Source < ActiveRecord::Base
</code></pre>
<p>Más información: <a href="http://agilewebdevelopment.com/plugins/annotate_models" title="http://agilewebdevelopment.com/plugins/annotate_models" id=link_0>http://agilewebdevelopment.com/plugins/annotate_models</a></p>
<h3>Instalar el plugin test_fixtures</h3>
<p>Este plugin, desarrollado por <a href="http://www.lacoctelera.com/ernesto-jimenez" title="http://www.lacoctelera.com/ernesto-jimenez" id=link_0>Ernesto Jiménez</a>, añade dinámicamente un test de las <em>fixturas</em> de cada uno de los modelos.</p>
<p>Más información: <a href="http://www.lacoctelera.com/ernesto-jimenez/post/2007/04/19/plugins-mi-propia-cosecha" title="http://www.lacoctelera.com/ernesto-jimenez/post/2007/04/19/plugins-mi-propia-cosecha" id=link_1>http://www.lacoctelera.com/ernesto-jimenez/post/2007/04/19/plugins-mi-propia-cosecha</a> </p>
<h3>Instalar el plugin memory_test_fix</h3>
<p>Se trata de un plugin que permite que los tests se ejecuten contra una base de datos cargada en memoria, lo cuál hace que vayan infinitamente más rápidos, algo muy recomendable si su número crece y crece.</p>
<p>Más información: <a href="http://agilewebdevelopment.com/plugins/memory_test_fix" title="http://agilewebdevelopment.com/plugins/memory_test_fix" id=link_3>http://agilewebdevelopment.com/plugins/memory_test_fix</a></p>
<p>Tanto este plugin como el anterior son ideales si vas a empezar un proyecto siguiendo la <a href="http://www.lacoctelera.com/dummyonrails/post/2007/06/08/test-driven-development" title="http://www.lacoctelera.com/dummyonrails/post/2007/06/08/test-driven-development" id=link_2>metodología <abbr title="Test Driven Development">TDD</abbr></a> </p>
<h3>Limpiar los ficheros database.yml y environment.rb</h3>
<p>Esto es más una manía que otra cosa, pero ambos ficheros vienen llenos de comentarios (muy instructivos y útiles, la verdad), pero que hace que ocupen infinitamente más de lo que deberían de ocupar.</p>
<p>Por ejemplo, mi <code>database.yml</code> es así:</p>
<pre><code class="ruby">
development:
  adapter: mysql
  database: vapor_development
  username: user
  password: pass
  host: localhost
test:
  adapter: sqlite3
  database: ":memory:"
</code></pre>
<p>Y mi <code>environment.rb</code> es así:</p>
<pre><code class="ruby">
RAILS_GEM_VERSION = '1.2.3' unless defined? RAILS_GEM_VERSION
require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
end
</code></pre>
<h3>Utilizar los generadores de Rails</h3>
<p>Los generadores de Rails son realmente útiles para crear las plantillas de los ficheros que vamos a utilizar: son mucho más limpios que el <em>scaffold</em> porque crean los ficheros vacíos, pero ya crean <em>fixturas</em>, controladores, tests, etcétera.</p>
<p>Especialmente recomendable el nuevo <code>script/generate resource item</code>, que nos creará nuestro modelo y nuestro controlador como un recursos, creando también las rutas asociadas.</p>
<h3>Copio el script rsql en mi carpeta de scripts</h3>
<p>El <em>script</em> <code>rsql</code> nos lo enseñó <a href="http://sobrerailes.com">Juan Lupión</a>, y si le dieran un céntimo por cada vez que lo utilizamos ya sería rico.</p>
<p>Se trata de un <em>script</em> de consola que toma como argumento el entorno (cogiendo por defecto <em>development</em> si no indicamos nada) y abre un cliente de SQL con los datos que lee del fichero <code>config/database.yml</code>, con lo cuál en lugar de un <code>mysql -u user -p password -h host databasename</code>, basta con hacer un <code>script/rsql production</code> para entrar en la base de datos de producción, por ejemplo.</p>
<p>El <em>script</em> no sé de donde es ni que licencia tiene, pero podéis descargar de <a href="http://www.lacoctelera.com/myfiles/inwebwetrust/rsql" title="http://www.lacoctelera.com/myfiles/inwebwetrust/rsql" id=link_1>aquí</a> una versión mejorada por el mismo Juan.</p>
<h3>The end</h3>
<p>Y eso es todo, hay cosas más personales y hay cosas que son un <strong>must do</strong>, pero seguro que os resultan útiles.</p>
<p>¿Y tú tienes algún consejo?
</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/06/09/cosas-hago-al-empezar-nuevo-proyecto-rails#comentarios
</comments>
</item>

<item>
<title>La Rails Conference 2007 de Oregón</title>
<link>http://www.inwebwetrust.net/post/2007/05/21/la-rails-conference-2007-oregon</link>
<pubDate>2007-05-21T08:39:42+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<category domain="http://www.inwebwetrust.net">Charlas y Presentaciones</category>
<content:encoded><![CDATA[<p>Ayer terminó <a href="http://conferences.oreillynet.com/rails/" title="http://conferences.oreillynet.com/rails/" id=link_0>la segunda conferencia Rails americana</a> , que ha tenido lugar en Portland, Oregon. Y ya están disponibles algunas de las <a href="http://www.web2expo.com/pub/w/51/presentations.html" title="http://www.web2expo.com/pub/w/51/presentations.html" id=link_1>presentaciones</a> para ser descargadas. </p>
<p>Si le echáis un vistazo por encima, así a bote pronto destacar la variedad: 2 presentaciones sobre testing, otro para sobre ActiionView, una de Joyent sobre el escalado de aplicaciones web (a la que le he echado un ojo y venía a echar un cable a los chicos de Twitter), REST, routing, y mucho más.</p>
<p>La verdad es que parecen bastante interesantes.</p>
<p>Y como anécdota, una pequeña broma sobre la presentación de David, <a href="http://www.jvoorhis.com/articles/2007/05/19/bingdoh" title="http://www.jvoorhis.com/articles/2007/05/19/bingdoh" id=link_2>un bingo con las buzzwords de su keynote</a>:</p>
<p><img src='http://www.inwebwetrust.net/myfiles/inwebwetrust/bingdoh.png' id='img_0' height='586' width='544' align='middle'/></p>
<p>A destacar <em>bastards</em> de entre todas ellas.
</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/05/21/la-rails-conference-2007-oregon#comentarios
</comments>
</item>

<item>
<title>15 atajos de teclados para Firefox en Mac OS X</title>
<link>http://www.inwebwetrust.net/post/2007/05/19/15-atajos-teclados-firefox-mac-os-x</link>
<pubDate>2007-05-19T16:11:36+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Snippets y Trucos</category>
<category domain="http://www.inwebwetrust.net">Mac OS X</category>
<content:encoded><![CDATA[<p>No los voy a traducir porque soy un vago, pero no dejéis de echárles un vistazo, que seguro que descubrís alguno nuevo:</p>
<p><a href="http://osxdaily.com/2007/05/18/15-must-know-firefox-shortcuts/" title="http://osxdaily.com/2007/05/18/15-must-know-firefox-shortcuts/" id=link_0>15 Must know Firefox shortcuts</a> </p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/05/19/15-atajos-teclados-firefox-mac-os-x#comentarios
</comments>
</item>

<item>
<title>Mejorando el control sobre los callbacks de ActiveRecord</title>
<link>http://www.inwebwetrust.net/post/2007/05/07/mejorando-control-sobre-callbacks-activerecord</link>
<pubDate>2007-05-07T00:07:30+00:00</pubDate>
<category domain="http://www.inwebwetrust.net">Ruby on Rails</category>
<content:encoded><![CDATA[<p><code>ActiveRecord</code>, la librería encargada en Rails de gestionar toda la capa de modelo de datos, incorpora de serie unos <a href="http://api.rubyonrails.com/classes/ActiveRecord/Callbacks.html" title="http://api.rubyonrails.com/classes/ActiveRecord/Callbacks.html" id=link_0><em>callbacks</em></a> que permiten controlar el ciclo de actualización de un objeto de manera más o menos precisa.</p>
<p>En el siguiente gráfico, extraído del <a href="http://www.pragmaticprogrammer.com/titles/rails/" title="http://www.pragmaticprogrammer.com/titles/rails/" id=link_1>Agile Web Development ed. 2</a>, se puede ver la jerarquía de <em>callbacks</em> y el orden en el que se ejecutan:</p>
<p><img src='http://www.inwebwetrust.net/myfiles/inwebwetrust/callbacks-rails.png' id='img_0' height='400' width='684' align='middle'/></p>
<p>Su uso es muy recomendable si queremos escribir un código limpio en los modelos de nuestra aplicación.</p>
<p>Sin embargo, hace unas semanas nos ha surgido la necesidad de ir un poco más allá en los <em>callbacks</em>. Os cuento la situación:</p>
<p>Imaginad un modelo <code>Post</code> y un modelo <code>Blog</code>. En el modelo <code>Blog</code>, tengo un atributo que me dice cuántos posts publicados tiene ese blog (un atributo desnormalizado). Pues bien, con un sencillo <code>after_save</code> en el modelo <code>Post</code> puedo conseguir mantener actualizado dicho campo sin mucho esfuerzo:</p>
<pre><code class="ruby">
class Post < ActiveRecord::Base
  ...
  def after_save
    blog.posts_count = Post.count(:conditions => ["blog_id = ? and status = ?", id, STATUS_PUBLISH])
    blog.save
  end
  ...
end
</code></pre>
<p>Este <em>callback</em> se ejecutará, efectivamente, cada vez que publique un post. Sin embargo, también lo hará cada vez que modifique un post que ya existe, para editar el contenido del mismo, o su título, atributos que no están relacionados con el blog al que pertenece el post.</p>
<p>Es decir, en realidad yo sólo quiero que se ejecute mi método <code>after_save</code> en un caso concreto: cuando se publica un post. O mejor dicho: <strong>cuando un post cambia de estado</strong>. El estado, o <em>status</em>, de un post simplemente indica si es un borrador o está publicado: si está en borrador, no aparece en los listados públicos y si está publicado sí. Por eso, el contador de posts del blog sólo se refiere a posts publicados.</p>
<p>Resumiendo: <strong>sólo quiero actualizar el blog asociado a un post cuando cambie el atributo <code>status</code> del mismo</strong>.</p>
<p>Y esto, amigos míos, <code>ActiveRecord</code> no lo permite, o por lo menos no de forma nativa. Pero con un poco de imaginación se puede llegar a saber dentro de un <em>callback</em> qué atributos se han modificado en el objeto.</p>
<p>Para ello, utilizaremos una variable de instancia (un atributo, vaya) al que llamaremos <code>before_update_attributes</code> y que va a hacer referencia a los atributos del objeto antes de la actualización. Lo declararemos y lo utilizaremos así:</p>
<pre><code class="ruby">
  attr_reader :before_update_attributes
  ...
  def before_validation
    ...
    @before_update_attributes = Post.find(id).attributes if id
  end
</code></pre>
<p>Es decir, en el <em>callback</em> <code>before_validation</code>, el primer <em>callback</em> de los que se ejecutan al modificar un objeto, vamos a guardar los valores de los atributos del objeto en nuestra variable para, posteriormente cuando nos haga falta, comparar los valores actuales con los que había previamente, antes de modificarlo.</p>
<p>Así, nuestro <code>after_save</code> podría quedar así:</p>
<pre><code class="ruby">
  def after_save
    # comprobamos que exista el before_update_attributes y que contenga el status
    return if before_update_attributes and not attributes.diff(before_update_attributes).keys.include?("status")
    # si no existe es que el objeto es nuevo
    # si no contiene el status, es que este atributo no se ha modificado
    blog.posts_count = Post.count(:conditions => ["blog_id = ? and status = ?", id, STATUS_PUBLISH])
    blog.save
  end
</code></pre>
<p>Y con este código, realizar los tests es realmente sencillo y no requiere realizar ninguna comprobación extraña, simplemente actualizar o no el <code>status</code> y verificar que se actualiza o no el atributo <code>posts_count</code> del blog.</p>
<p>Reconozco que no es la forma más elegante y que se podría mejorar e incluso generalizar de alguna manera (¿alguien se anima a hacer un <em>plugin</em>?), pero como primera aproximación parida en el tren camino a Valencia no está mal.</p>
<p>Así que animáos a opinar y, sobretodo, me interesa saber si conocéis alguna manera de abordar este problema de otra forma diferente.
</p>
]]></content:encoded>
<comments>
http://www.inwebwetrust.net/post/2007/05/07/mejorando-control-sobre-callbacks-activerecord#comentarios
</comments>
</item>
 
</channel>
</rss>
