<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>El Futirifoken &#187; observer</title>
	<atom:link href="http://www.gazer.com.ar/tag/observer/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.gazer.com.ar</link>
	<description>El arte de no decir nada ;-)</description>
	<lastBuildDate>Mon, 26 Dec 2011 19:56:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Refactoring de &#8220;Fat Methods&#8221; &#8211; Episodio 3</title>
		<link>http://www.gazer.com.ar/2008/10/30/refactoring-de-fat-methods-episodio-3/</link>
		<comments>http://www.gazer.com.ar/2008/10/30/refactoring-de-fat-methods-episodio-3/#comments</comments>
		<pubDate>Thu, 30 Oct 2008 11:44:09 +0000</pubDate>
		<dc:creator>Gazer</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[observer]]></category>
		<category><![CDATA[refactoring]]></category>

		<guid isPermaLink="false">http://www.gazer.com.ar/?p=358</guid>
		<description><![CDATA[En el Episodio 1 trabajé el método Matches#create y había dejado una parte a la que Des preguntó por qué la ignoraba. En ese momento no quería extender mucho más el post por lo que en esta oportunidad vamos a completar el refactoring pendiente. El código que habíamos logrado en ese momento es el siguiente: [...]]]></description>
			<content:encoded><![CDATA[<p>En el <a href="http://www.gazer.com.ar/2008/10/02/refactoring-de-fat-methods-episodio-1/">Episodio 1</a> trabajé el método <code>Matches#create</code> y había dejado una parte a la que <a href="http://www.gazer.com.ar/2008/10/02/refactoring-de-fat-methods-episodio-1/#comment-32897">Des</a> preguntó por qué la ignoraba. En ese momento no quería extender mucho más el post por lo que en esta oportunidad vamos a completar el refactoring pendiente.</p>
<p>El código que habíamos logrado en ese momento es el siguiente:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">  <span style="color:#9966CC; font-weight:bold;">def</span> create
    <span style="color:#0066ff; font-weight:bold;">@match</span> = current_user.<span style="color:#9900CC;">matches</span>.<span style="color:#9900CC;">create</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:match</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
    <span style="color:#0066ff; font-weight:bold;">@notifications</span> = <span style="color:#0066ff; font-weight:bold;">@match</span>.<span style="color:#9900CC;">owner</span>.<span style="color:#9900CC;">friends</span>.<span style="color:#CC0066; font-weight:bold;">select</span> <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">|</span>f<span style="color:#006600; font-weight:bold;">|</span> f.<span style="color:#9900CC;">notify_new_matches</span>? <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">collect</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&amp;</span>email<span style="color:#006600; font-weight:bold;">&#41;</span>
    Emailer.<span style="color:#9900CC;">deliver_match_created</span><span style="color:#006600; font-weight:bold;">&#40;</span>@match, <span style="color:#0066ff; font-weight:bold;">@notifications</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#0066ff; font-weight:bold;">@notifications</span>.<span style="color:#9900CC;">any</span>?
&nbsp;
    flash<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:success</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#996600;">&quot;El partido fue creado.&quot;</span>
    redirect_to matches_path
  <span style="color:#9966CC; font-weight:bold;">rescue</span>
    render <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'new'</span>
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Lo que nos quedaba terminar era cómo mejorar el envío de las notificaciones para aquellos amigos que tenían activa dicha opción. Como primer paso vamos a separar la lógica del mailer de manera que no quede mezclado en el controller, y ya que estamos, que no importa donde se cree un partido el email salga igual sin la necesidad de copiar y pegar código.</p>
<p>Una opción es usar un callback <code>after_create</code> como ya hicimos en el post pasado, pero a mi no me gusta mezclar en los modelos lógica que no tiene que ver con la persistencia. La razón es que esta tarea de enviar emails no es algo propio de un modelo, no debería tener esa responsabilidad. Pero dejarla en el controller sería &#8220;irresponsable&#8221; <img src='http://www.gazer.com.ar/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> .</p>
<p>Una opción, no muy acertada, podría ser usa un filtro que se ejecute después del <code>create</code> (<code>after_filter</code>) pero quizás no siempre tendríamos la posibilidad de ejecutar un filtro. La mejor opción es utilizar un <code>Observer</code> para mirar al modelo <code>Match</code>, y cuando uno nuevo es creado, ejecutar nuestro código.</p>
<p>Los Observers se registran a si mismos a un modelo dado escuchando los callbacks que nosotros definamos. Estos callbacks son los mismos que existen en <code>ActiveRecord</code>, siendo algunos : after_create, before_create, after_save, etc&#8230;</p>
<p>Como vemos, el <code>Observer</code> es casi lo mismo (a nivel práctico claro está) que usar los callbacks de <code>ActiveRecord</code> pero sin tener que mezclar acciones que no son propias de los modelos. Muchas veces uno se olvida que existen ya que generalmente se los utiliza para las estrategias de invalidación de cache (que puntualmente estos observers se llaman Sweepers).</p>
<p>El código del observer quedaría ahora :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">  <span style="color:#008000; font-style:italic;"># app/model/match_observer.rb</span>
  <span style="color:#9966CC; font-weight:bold;">class</span> MatchObserver <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Observer</span>
    <span style="color:#9966CC; font-weight:bold;">def</span> after_create<span style="color:#006600; font-weight:bold;">&#40;</span>contact<span style="color:#006600; font-weight:bold;">&#41;</span>
      <span style="color:#0066ff; font-weight:bold;">@notifications</span> = <span style="color:#0066ff; font-weight:bold;">@match</span>.<span style="color:#9900CC;">owner</span>.<span style="color:#9900CC;">friends</span>.<span style="color:#CC0066; font-weight:bold;">select</span> <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">|</span>f<span style="color:#006600; font-weight:bold;">|</span> f.<span style="color:#9900CC;">notify_new_matches</span>? <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">collect</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&amp;</span>:email<span style="color:#006600; font-weight:bold;">&#41;</span>
      Emailer.<span style="color:#9900CC;">deliver_match_created</span><span style="color:#006600; font-weight:bold;">&#40;</span>@match, <span style="color:#0066ff; font-weight:bold;">@notifications</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#0066ff; font-weight:bold;">@notifications</span>.<span style="color:#9900CC;">any</span>?
    <span style="color:#9966CC; font-weight:bold;">end</span>
 <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Como se ve, en ningún lugar hacemos referencia al modelo observado. Esto es porque Rails lo infiere automáticamente a partir del nombre del <code>Observer</code>. Claro está que si por alguna razón usamos un nombre que no permita inferirlo lo podemos especificar.</p>
<p>Lo único que faltaría es decirle a Rails que existe el <code>Observer</code>, para que lo cargue y lo registre con la clase correspondiente. Para eso debemos agregar en nuestros environment lo siguiente :
</pre>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">  config.<span style="color:#9900CC;">active_record</span>.<span style="color:#9900CC;">observers</span> = <span style="color:#ff3333; font-weight:bold;">:match_observer</span></pre></div></div>

<p>Ahora si, veamos como quedó nuestro controlador totalmente refactorizado :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">  <span style="color:#008000; font-style:italic;"># Dentro de matches_controllers.rb</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> create
    <span style="color:#0066ff; font-weight:bold;">@match</span> = current_user.<span style="color:#9900CC;">matches</span>.<span style="color:#9900CC;">create</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:match</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    flash<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:success</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#996600;">&quot;El partido fue creado.&quot;</span>
&nbsp;
    redirect_to matches_path
  <span style="color:#9966CC; font-weight:bold;">rescue</span>
    render <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'new'</span>
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Ahora si nuestro controlador está bastante mejor. Para la próxima entrega vamos a como mejorar las asociaciones de los modelos para poder cambiar el <code>match.owner.friends.select</code> que no es para nada prolijo.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gazer.com.ar/2008/10/30/refactoring-de-fat-methods-episodio-3/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Usando Rails.cache en 2.1.x</title>
		<link>http://www.gazer.com.ar/2008/10/21/usando-rails-cache/</link>
		<comments>http://www.gazer.com.ar/2008/10/21/usando-rails-cache/#comments</comments>
		<pubDate>Wed, 22 Oct 2008 01:46:00 +0000</pubDate>
		<dc:creator>Gazer</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[observer]]></category>
		<category><![CDATA[ruby on rails]]></category>

		<guid isPermaLink="false">http://www.gazer.com.ar/?p=400</guid>
		<description><![CDATA[Para uno de los sitios que tenemos montados llegó la hora de optimizar algunas partes para descargar la DB un poco. Lo primero (y por ahora único ) que se hizo fue cachear la instancia que representa a la Etapa actual del juego en memoria, para así no cargarla en cada request. El código original [...]]]></description>
			<content:encoded><![CDATA[<p>Para uno de los sitios que tenemos montados llegó la hora de optimizar algunas partes para descargar la DB un poco. Lo primero (y por ahora único <img src='http://www.gazer.com.ar/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> ) que se hizo fue cachear la instancia que representa a la Etapa actual del juego en memoria, para así no cargarla en cada request.</p>
<p>El código original era :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Stage <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">current</span>
    t = <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span>.<span style="color:#9900CC;">utc</span>
    find<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:first</span>, <span style="color:#ff3333; font-weight:bold;">:conditions</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;start_at &lt; = ? AND end_at &gt;= ?&quot;</span>, t, t<span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>y lo cambiamos para usar el nuevo sistema de cache de Rails 2.1.x que realmente fue simplificado. Hay varios sitio donde hablan sobre el cache en 2.1, les recomiendo mirar el <a href="http://railscasts.com/episodes/115">screencast</a> de RailsCasts y <a href="http://ryandaigle.com/articles/2007/12/19/what-s-new-in-edge-rails-pluggable-controller-caching">este</a> y <a href="http://thewebfellas.com/blog/2008/6/9/rails-2-1-now-with-better-integrated-caching">este</a> post.</p>
<p>El código modificado quedó como se muestra a continuación.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#008000; font-style:italic;"># config.environment.rb</span>
config.<span style="color:#9900CC;">cache_store</span> = <span style="color:#ff3333; font-weight:bold;">:mem_cache_store</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># app/models/stage.rb</span>
<span style="color:#9966CC; font-weight:bold;">class</span> Stage <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">current</span>
    <span style="color:#0066ff; font-weight:bold;">@current</span> = Rails.<span style="color:#9900CC;">cache</span>.<span style="color:#9900CC;">read</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'stage_current'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
    <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#0066ff; font-weight:bold;">@current</span>.<span style="color:#0000FF; font-weight:bold;">nil</span>? <span style="color:#006600; font-weight:bold;">||</span> <span style="color:#0066ff; font-weight:bold;">@current</span>.<span style="color:#9900CC;">closed</span>?
      t = <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span>.<span style="color:#9900CC;">utc</span>
      <span style="color:#0066ff; font-weight:bold;">@current</span> = find<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:first</span>, <span style="color:#ff3333; font-weight:bold;">:conditions</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;start_at &lt; = ? AND end_at &gt;= ?&quot;</span>, t, t<span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
      Rails.<span style="color:#9900CC;">cache</span>.<span style="color:#9900CC;">write</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'stage_current'</span>, <span style="color:#0066ff; font-weight:bold;">@current</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#0066ff; font-weight:bold;">@current</span>
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>La condición del <code>if</code> es necesaria por dos motivos : la primera por si el cache fue limpiado y la segunda para invalidar el valor guardado actualmente si la etapa eterminó, para que la nueva etapa pase a ocupar el cache.</p>
<p>En este caso estamos usando MemCache como CacheStore ya que se comparte entre más de un webserver y simplifica expirar el cache.</p>
<p>Lo único que resta es expirar el cache en caso de que cambie el modelo, que además de la fecha de finalización contiene textos que son usados en la web (como las bases y condiciones, premios, etc). Para eso creamos un Observer que se encargue de eso cuando una etapa es guardada y además es la etapa actual (si no, no tiene sentido hacer nada) :</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#008000; font-style:italic;"># app/models/stage_observer.rb</span>
<span style="color:#9966CC; font-weight:bold;">class</span> StageObserver <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Observer</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> after_save<span style="color:#006600; font-weight:bold;">&#40;</span>stage<span style="color:#006600; font-weight:bold;">&#41;</span>
    Rails.<span style="color:#9900CC;">cache</span>.<span style="color:#9900CC;">delete</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'stage_current'</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">if</span> stage.<span style="color:#9900CC;">is_current</span>?
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># config/environment.rb</span>
config.<span style="color:#9900CC;">active_record</span>.<span style="color:#9900CC;">observers</span> = <span style="color:#ff3333; font-weight:bold;">:stage_observer</span></pre></div></div>

<p>Con esto bajó bastante el uso de la DB (prácticamente no se puede hacer nada en el sitio sin consultar la etapa actual). Ahora tengo que ver que le pasa a la DB que a veces respondes después de 3 segs :S, pero eso ya escapa a programar <img src='http://www.gazer.com.ar/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.gazer.com.ar/2008/10/21/usando-rails-cache/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

