<?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>@lobo_tuerto</title>
	<atom:link href="http://lobotuerto.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://lobotuerto.com/blog</link>
	<description>Full Stack Developer — Specializing Generalist — UI Engineering</description>
	<lastBuildDate>Sun, 31 Dec 2017 07:26:30 +0000</lastBuildDate>
	<language>es-ES</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.9.1</generator>
<site xmlns="com-wordpress:feed-additions:1">2437480</site>	<item>
		<title>i3 — Un ambiente de trabajo para power users</title>
		<link>http://lobotuerto.com/blog/2017/12/05/i3-un-ambiente-de-trabajo-para-power-users/</link>
		<comments>http://lobotuerto.com/blog/2017/12/05/i3-un-ambiente-de-trabajo-para-power-users/#respond</comments>
		<pubDate>Tue, 05 Dec 2017 22:51:21 +0000</pubDate>
		<dc:creator><![CDATA[lobo_tuerto]]></dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[recomendaciones]]></category>

		<guid isPermaLink="false">http://lobotuerto.com/blog/?p=6836</guid>
		<description><![CDATA[Adiós GNOME, adiós Unity&#8230; hola i3. Si obsesionas un poco sobre un ambiente de trabajo óptimo, tratando de encontrar cuál será el mejor layout para los espacios de trabajo virtuales, cómo acomodar las ventanas, etc.; deberías entonces probar i3. Échale un ojo a lo que ofrece en estos videos, no te vas a decepcionar, te &#8230; <p class="link-more"><a href="http://lobotuerto.com/blog/2017/12/05/i3-un-ambiente-de-trabajo-para-power-users/" class="more-link">Continuar leyendo<span class="screen-reader-text"> "i3 — Un ambiente de trabajo para <em>power users</em>"</span></a></p>]]></description>
				<content:encoded><![CDATA[<p>Adiós GNOME, adiós Unity&#8230; hola <strong>i3</strong>.</p>
<p>Si obsesionas un poco sobre un ambiente de trabajo óptimo, tratando de encontrar cuál será el mejor layout para los espacios de trabajo virtuales, cómo acomodar las ventanas, etc.; deberías entonces probar <strong>i3</strong>.</p>
<p>Échale un ojo a lo que ofrece en estos videos, no te vas a decepcionar, te lo aseguro.</p>
<p><iframe class='youtube-player' type='text/html' width='525' height='326' src='http://www.youtube.com/embed/j1I63wGcvU4?version=3&#038;rel=1&#038;fs=1&#038;autohide=2&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;start=22&#038;wmode=transparent' allowfullscreen='true' style='border:0;'></iframe></p>
<p><iframe class='youtube-player' type='text/html' width='525' height='326' src='http://www.youtube.com/embed/8-S0cWnLBKg?version=3&#038;rel=1&#038;fs=1&#038;autohide=2&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' allowfullscreen='true' style='border:0;'></iframe></p>
<p><iframe class='youtube-player' type='text/html' width='525' height='326' src='http://www.youtube.com/embed/ARKIwOlazKI?version=3&#038;rel=1&#038;fs=1&#038;autohide=2&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;start=1907&#038;wmode=transparent' allowfullscreen='true' style='border:0;'></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://lobotuerto.com/blog/2017/12/05/i3-un-ambiente-de-trabajo-para-power-users/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<post-id xmlns="com-wordpress:feed-additions:1">6836</post-id>	</item>
		<item>
		<title>Yo más te adoro</title>
		<link>http://lobotuerto.com/blog/2017/05/17/6790/</link>
		<comments>http://lobotuerto.com/blog/2017/05/17/6790/#respond</comments>
		<pubDate>Thu, 18 May 2017 01:25:24 +0000</pubDate>
		<dc:creator><![CDATA[lobo_tuerto]]></dc:creator>
				<category><![CDATA[Sin categoría]]></category>

		<guid isPermaLink="false">http://lobotuerto.com/blog/?p=6790</guid>
		<description><![CDATA[]]></description>
				<content:encoded><![CDATA[<p><iframe class='youtube-player' type='text/html' width='525' height='326' src='http://www.youtube.com/embed/pqJBXjzBr_U?version=3&#038;rel=1&#038;fs=1&#038;autohide=2&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' allowfullscreen='true' style='border:0;'></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://lobotuerto.com/blog/2017/05/17/6790/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<post-id xmlns="com-wordpress:feed-additions:1">6790</post-id>	</item>
		<item>
		<title>Rails 5 JSON API con RethinkDB</title>
		<link>http://lobotuerto.com/blog/2016/10/22/rails-json-api-con-rethinkdb/</link>
		<comments>http://lobotuerto.com/blog/2016/10/22/rails-json-api-con-rethinkdb/#respond</comments>
		<pubDate>Sat, 22 Oct 2016 05:35:17 +0000</pubDate>
		<dc:creator><![CDATA[lobo_tuerto]]></dc:creator>
				<category><![CDATA[guías]]></category>
		<category><![CDATA[Sin categoría]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rethinkdb]]></category>

		<guid isPermaLink="false">http://lobotuerto.com/blog/?p=6654</guid>
		<description><![CDATA[Con Rails 5 fuera y el nuevo modo API incluido en el framework, veamos que se necesita para configurar una nueva aplicación para que funja como una JSON API. En esta guía se explica cómo crear y configurar una aplicación Rails con RethinkDB, de tal manera que funcione como una JSON API (puro back-end). Una &#8230; <p class="link-more"><a href="http://lobotuerto.com/blog/2016/10/22/rails-json-api-con-rethinkdb/" class="more-link">Continuar leyendo<span class="screen-reader-text"> "Rails 5 JSON API con RethinkDB"</span></a></p>]]></description>
				<content:encoded><![CDATA[<p>Con Rails 5 fuera y el nuevo modo API incluido en el framework, veamos que se necesita para configurar una nueva aplicación para que funja como una JSON API.</p>
<p>En esta guía se explica cómo crear y configurar una aplicación <a href="http://rubyonrails.org/" title="Ruby on Rails">Rails</a> con <a href="https://www.rethinkdb.com/">RethinkDB</a>, de tal manera que funcione como una <strong>JSON API</strong> (puro <em><a href="http://en.wikipedia.org/wiki/Front_and_back_ends" title="Front and back ends">back-end</a></em>).</p>
<p>Una aplicación de este tipo se da muy bien para después emplearla con múltiples clientes, ya sean <a href="http://en.wikipedia.org/wiki/Single-page_application" title="Single-page application">SPAs</a> (<em>Single Page Applications</em>) hechas en <a href="https://angular.io/">Angular</a> o aplicaciones móviles construidas con <a href="https://ionicframework.com/docs/v2/">Ionic 2</a>, <em>wink-wink</em>.</p>
<p>Se asume familiaridad con <strong>Rails</strong>, <strong>git</strong> y los <a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes" title="List of HTTP status codes">códigos de estado HTTP</a>.</p>
<h1>Preliminares</h1>
<ul>
<li><a href="http://lobotuerto.com/blog/2012/10/07/como-instalar-ruby-con-rbenv-en-ubuntu/" title="Cómo instalar Ruby con rbenv en Ubuntu">Instala Ruby</a></li>
<li><a href="https://www.rethinkdb.com/docs/install/ubuntu/">Install RethinkDB on Ubuntu</a></li>
</ul>
<h1>Commit inicial</h1>
<p>Para generar el proyecto y hacer el primer <em>commit</em>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rails new json_api <span class="re5">--api</span> <span class="re5">--skip-active-record</span>
<span class="kw3">cd</span> json_api
<span class="kw2">git init</span>
<span class="kw2">git add</span> .
<span class="kw2">git</span> ci <span class="re5">-m</span> <span class="st0">&quot;Commit inicial.&quot;</span></pre></div></div></div></div></div></div></div>


<p>La opción de <strong>&#8211;skip-active-record</strong> desactiva <strong>ActiveRecord</strong> porque usaremos <strong>RethinkDB</strong> con <strong><a href="http://nobrainer.io/">NoBrainer</a></strong> en lugar de una base de datos relacional como <strong>PostgreSQL</strong>.</p>
<h1>Configuración inicial</h1>
<p>Agrega estas gemas a tu <strong>Gemfile</strong>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">group <span class="re3">:development</span>, <span class="re3">:test</span> <span class="kw1">do</span>
  <span class="co1">#...</span>
  <span class="co1"># Framework para pruebas</span>
  gem <span class="st0">'minitest-rails'</span>
  <span class="co1"># Para generar objetos de prueba</span>
  gem <span class="st0">'fabrication'</span>
  <span class="co1"># Para generar datos aleatorios</span>
  gem <span class="st0">'faker'</span>
<span class="kw1">end</span>
&nbsp;
<span class="co1">#...</span>
<span class="co1"># Para usar RethinkDB a través de NoBrainer</span>
gem <span class="st0">'nobrainer'</span>
<span class="co1"># Para construir JSON APIs con facilidad</span>
gem <span class="st0">'jbuilder'</span>, <span class="st0">'~&gt; 2.5'</span>
<span class="co1"># Para usar ActiveModel has_secure_password</span>
gem <span class="st0">'bcrypt'</span>, <span class="st0">'~&gt; 3.1.7'</span></pre></div></div></div></div></div></div></div>


<p>Después en la terminal:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">bundle
rails g minitest:install
rails g nobrainer:install</pre></div></div></div></div></div></div></div>


<p>Con esto se instalan las gemas que hagan falta, después se generan los archivos de configuración para <strong>Minitest</strong> y <strong>NoBrainer</strong>.<br />
Al ejecutar el generador de <strong>Minitest</strong>, te va a preguntar si debe sobreescribir el archivo <strong>test_helper.rb</strong>, contesta sí.</p>
<p>Agrega este contenido al archivo <strong>config/application.rb</strong>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">config.<span class="me1">generators</span> <span class="kw1">do</span> <span class="sy0">|</span>g<span class="sy0">|</span>
  <span class="co1"># Framework de pruebas estilo BDD</span>
  g.<span class="me1">test_framework</span> <span class="re3">:minitest</span>, spec: <span class="kw2">true</span>, fixture_replacement: <span class="re3">:fabrication</span>
  g.<span class="me1">fixture_replacement</span> <span class="re3">:fabrication</span>, dir: <span class="st0">'test/fabricators'</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>En el archivo <strong>test/test_helper.rb</strong>, comenta la siguiente línea:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="co1"># fixtures :all</span></pre></div></div></div></div></div></div></div>


<p>No tenemos disponible <strong>ActiveRecord</strong>, si no se comentan esas líneas al tratar de ejecutar las pruebas se lanzará una excepción.</p>
<p>En el archivo <strong>config/initializers/inflections.rb</strong> agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">ActiveSupport::<span class="kw4">Inflector</span>.<span class="me1">inflections</span><span class="br0">&#40;</span> <span class="re3">:en</span> <span class="br0">&#41;</span> <span class="kw1">do</span> <span class="sy0">|</span>inflect<span class="sy0">|</span>
  inflect.<span class="me1">acronym</span> <span class="st0">'API'</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Esto permite que al generar los controladores se utilice <strong>API</strong> como nombre del módulo contenedor en lugar de <strong>Api</strong>.</p>
<p>Con la configuración inicial terminada, agrega los cambios al repo:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1"><span class="kw2">git add</span> .
<span class="kw2">git</span> ci <span class="re5">-m</span> <span class="st0">&quot;Configuración inicial.&quot;</span></pre></div></div></div></div></div></div></div>


<h1>Testing</h1>
<h2>TDD vs BDD</h2>
<p>La diferencia entre los dos es el cómo te gusta pensar cuando modelas tu aplicación.</p>
<p>El TDD utiliza el <strong>es</strong> (<em>assert</em>), el BDD usa el <strong>debe ser</strong> (<em>must</em>). Básicamente es una cuestión de <strong>ser</strong> vs <strong>debe ser</strong> al modelar.</p>
<h2>Behavior-driven development</h2>
<p>Si lo tuyo es el TDD, pasa a la siguiente sección.</p>
<h3>Genera tu primer controlador</h3>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rails g controller API::Users</pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>test/controllers/api/users_controller_test.rb</strong> y cambia el test de ejemplo por:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">it <span class="st0">&quot;#index debe ser exitoso&quot;</span> <span class="kw1">do</span>
  get api_users_url
  response.<span class="me1">status</span>.<span class="me1">must_equal</span> <span class="nu0">200</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>config/routes.rb</strong> para agregar el recurso:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">namespace <span class="re3">:api</span> <span class="kw1">do</span>
  resources <span class="re3">:users</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>app/controllers/api/users_controller.rb</strong> y agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw1">def</span> index
  render json: <span class="br0">&#123;</span><span class="br0">&#125;</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p><img src="https://s.w.org/images/core/emoji/2.3/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Esta fue una muestra de un proceso muy básico de BDD para un controlador.</p>
<h3>Genera tu primer modelo</h3>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rails g model User name:string email:string password_digest:string</pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Abre el archivo <strong>test/models/user_test.rb</strong> y verás:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw3">require</span> <span class="st0">&quot;test_helper&quot;</span>
&nbsp;
describe User <span class="kw1">do</span>
  let<span class="br0">&#40;</span><span class="re3">:user</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> User.<span class="me1">new</span> <span class="br0">&#125;</span>
&nbsp;
  it <span class="st0">&quot;must be valid&quot;</span> <span class="kw1">do</span>
    value<span class="br0">&#40;</span>user<span class="br0">&#41;</span>.<span class="me1">must_be</span> <span class="re3">:valid</span>?
  <span class="kw1">end</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Si analizamos un poco la situación y contemplamos nuestro modelo <strong>User</strong>, veremos que el usuario forzosamente necesita al menos un correo. Así, un usuario recién creado debería ser inválido.</p>
<p>Cambia el contenido de ese archivo por este:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw3">require</span> <span class="st0">'test_helper'</span>
&nbsp;
describe User <span class="kw1">do</span>
  let<span class="br0">&#40;</span><span class="re3">:user</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> User.<span class="me1">new</span> <span class="br0">&#125;</span>
&nbsp;
  it <span class="st0">'no debe ser válido'</span> <span class="kw1">do</span>
    value<span class="br0">&#40;</span>user<span class="br0">&#41;</span>.<span class="me1">wont_be</span> <span class="re3">:valid</span>?
  <span class="kw1">end</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Abre el archivo <strong>app/models/user.rb</strong> y agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">validates <span class="re3">:email</span>, presence: <span class="kw2">true</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p><img src="https://s.w.org/images/core/emoji/2.3/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Esto fue una muestra de un proceso muy básico de aplicación de BDD para crear un modelo.</p>
<p>A continuación veremos cómo se haría con TDD.</p>
<h2>Test-driven development</h2>
<p>Para que los archivos de las pruebas se generen al estilo TDD cambia el valor de <em>spec</em> a <em>false</em> en el archivo <strong>config/application.rb</strong>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">config.<span class="me1">generators</span> <span class="kw1">do</span> <span class="sy0">|</span>g<span class="sy0">|</span>
  <span class="co1"># Framework de pruebas estilo TDD</span>
  g.<span class="me1">test_framework</span> <span class="re3">:minitest</span>, spec: <span class="kw2">false</span>, fixture_replacement: <span class="re3">:fabrication</span>
  g.<span class="me1">fixture_replacement</span> <span class="re3">:fabrication</span>, dir: <span class="st0">'test/fabricators'</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<h3>Genera tu primer controlador</h3>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rails g controller API::Users</pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>test/controllers/api/users_controller_test.rb</strong> y cambia el test de ejemplo por:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw1">def</span> test_index_action
  get api_users_url
  assert_response <span class="re3">:success</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p><em>Nota: El nombre de los métodos debe comenzar necesariamente con <strong>test_</strong> para que sean ejecutados durante el proceso de pruebas.</em></p>
<p>El método anterior es equivalente a este:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">test <span class="st0">'index action'</span> <span class="kw1">do</span>
  get api_users_url
  assert_response <span class="re3">:success</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>config/routes.rb</strong> para agregar el recurso:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">namespace <span class="re3">:api</span> <span class="kw1">do</span>
  resources <span class="re3">:users</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>app/controllers/api/users_controller.rb</strong> y agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw1">def</span> index
  render json: <span class="br0">&#123;</span><span class="br0">&#125;</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p><img src="https://s.w.org/images/core/emoji/2.3/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Esta fue una muestra de un proceso muy básico de TDD para un controlador.</p>
<h3>Genera tu primer modelo</h3>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rails g model User name:string email:string password_digest:string</pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Abre el archivo <strong>test/models/user_test.rb</strong> y verás:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw3">require</span> <span class="st0">&quot;test_helper&quot;</span>
&nbsp;
<span class="kw1">class</span> UserTest <span class="sy0">&lt;</span> <span class="re2">ActiveSupport::TestCase</span>
  <span class="kw1">def</span> user
    <span class="re1">@user</span> <span class="sy0">||</span>= User.<span class="me1">new</span>
  <span class="kw1">end</span>
&nbsp;
  <span class="kw1">def</span> test_valid
    assert user.<span class="me1">valid</span>?
  <span class="kw1">end</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Si analizamos un poco la situación y contemplamos nuestro modelo <strong>User</strong>, veremos que el usuario forzosamente necesita al menos un correo. Así, un usuario recién creado debería ser inválido.</p>
<p>Cambia el único test que existe en ese archivo por este otro:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw1">def</span> test_invalid
  assert_not user.<span class="me1">valid</span>?
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Abre el archivo <strong>app/models/user.rb</strong> y agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">validates <span class="re3">:email</span>, presence: <span class="kw2">true</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p><img src="https://s.w.org/images/core/emoji/2.3/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Y esta fue una muestra de un proceso muy básico de TDD para un modelo.</p>
<p>TDD o BDD es una cuestión de gustos. En lo personal prefiero el BDD.</p>
<p>Espero esta guía te sea útil.</p>
<h1>Repositorio en github</h1>
<p><a href="https://github.com/lobo-tuerto/rails_rethinkdb">lobo-tuerto/rails_rethinkdb</a></p>
]]></content:encoded>
			<wfw:commentRss>http://lobotuerto.com/blog/2016/10/22/rails-json-api-con-rethinkdb/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<post-id xmlns="com-wordpress:feed-additions:1">6654</post-id>	</item>
		<item>
		<title>Katy Perry &#8211; Rise</title>
		<link>http://lobotuerto.com/blog/2016/10/11/katy-perry-rise/</link>
		<comments>http://lobotuerto.com/blog/2016/10/11/katy-perry-rise/#respond</comments>
		<pubDate>Tue, 11 Oct 2016 23:58:20 +0000</pubDate>
		<dc:creator><![CDATA[lobo_tuerto]]></dc:creator>
				<category><![CDATA[videos]]></category>
		<category><![CDATA[youtube]]></category>

		<guid isPermaLink="false">http://lobotuerto.com/blog/?p=6646</guid>
		<description><![CDATA[]]></description>
				<content:encoded><![CDATA[<p><iframe class='youtube-player' type='text/html' width='525' height='326' src='http://www.youtube.com/embed/hdw1uKiTI5c?version=3&#038;rel=1&#038;fs=1&#038;autohide=2&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;wmode=transparent' allowfullscreen='true' style='border:0;'></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://lobotuerto.com/blog/2016/10/11/katy-perry-rise/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<post-id xmlns="com-wordpress:feed-additions:1">6646</post-id>	</item>
		<item>
		<title>Mejorando el $log de AngularJS con decorators</title>
		<link>http://lobotuerto.com/blog/2016/03/12/mejorando-el-log-de-angularjs-con-decorators/</link>
		<comments>http://lobotuerto.com/blog/2016/03/12/mejorando-el-log-de-angularjs-con-decorators/#respond</comments>
		<pubDate>Sat, 12 Mar 2016 22:32:29 +0000</pubDate>
		<dc:creator><![CDATA[lobo_tuerto]]></dc:creator>
				<category><![CDATA[programación]]></category>
		<category><![CDATA[Sin categoría]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[$log]]></category>
		<category><![CDATA[angularjs]]></category>
		<category><![CDATA[decorator]]></category>
		<category><![CDATA[enhanced]]></category>
		<category><![CDATA[improved]]></category>
		<category><![CDATA[logger]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[mejorado]]></category>

		<guid isPermaLink="false">http://lobotuerto.com/blog/?p=6562</guid>
		<description><![CDATA[La idea de este artículo es contar con un servicio de logging que nos permita contextualizar fácilmente la información que aparece en la consola del navegador. A continuación pongo unos ejemplos para ilustrar su uso: Uso básico: $log.debug&#40; 'línea debug' &#41;; $log.info&#40; 'línea info' &#41;; Salida: [0] -- 12/3/2016 15:43:38 línea debug [1] -- 12/3/2016 &#8230; <p class="link-more"><a href="http://lobotuerto.com/blog/2016/03/12/mejorando-el-log-de-angularjs-con-decorators/" class="more-link">Continuar leyendo<span class="screen-reader-text"> "Mejorando el $log de AngularJS con decorators"</span></a></p>]]></description>
				<content:encoded><![CDATA[<p>La idea de este artículo es contar con un servicio de <em>logging</em> que nos permita contextualizar fácilmente la información que aparece en la consola del navegador.</p>
<p>A continuación pongo unos ejemplos para ilustrar su uso:</p>
<p>Uso básico:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="javascript"><pre class="de1">$log.<span class="me1">debug</span><span class="br0">&#40;</span> <span class="st0">'línea debug'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
$log.<span class="me1">info</span><span class="br0">&#40;</span> <span class="st0">'línea info'</span> <span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>Salida:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="text"><pre class="de1">[0] -- 12/3/2016 15:43:38 línea debug
[1] -- 12/3/2016 15:43:38 línea info</pre></div></div></div></div></div></div></div>


<p>Uso con contextos:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="javascript"><pre class="de1"><span class="kw1">var</span> logger <span class="sy0">=</span> $log.<span class="me1">getLogger</span><span class="br0">&#40;</span> <span class="st0">'MainController'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger.<span class="me1">debug</span><span class="br0">&#40;</span> <span class="st0">'línea 1'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger.<span class="me1">debug</span><span class="br0">&#40;</span> <span class="st0">'línea 2'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger.<span class="me1">debug</span><span class="br0">&#40;</span> <span class="st0">'línea 3'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="kw1">var</span> logger2 <span class="sy0">=</span> $log.<span class="me1">getLogger</span><span class="br0">&#40;</span> <span class="st0">'App'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger2.<span class="me1">debug</span><span class="br0">&#40;</span> <span class="st0">'otra línea'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger2.<span class="me1">debug</span><span class="br0">&#40;</span> <span class="st0">'una línea más'</span> <span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>Salida:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="text"><pre class="de1">[0] -- 12/3/2016 15:58:05 -- [MainController]:0&gt;  línea 1
[1] -- 12/3/2016 15:58:05 -- [MainController]:1&gt;  línea 2
[2] -- 12/3/2016 15:58:05 -- [MainController]:2&gt;  línea 3
[3] -- 12/3/2016 15:58:05 -- [App]:0&gt;  otra línea
[4] -- 12/3/2016 15:58:05 -- [App]:1&gt;  una línea más</pre></div></div></div></div></div></div></div>


<p>Con desactivación de contextos:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="javascript"><pre class="de1"><span class="kw1">var</span> logger <span class="sy0">=</span> $log.<span class="me1">getLogger</span><span class="br0">&#40;</span> <span class="st0">'MainController'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger.<span class="me1">enable</span><span class="br0">&#40;</span> <span class="kw2">false</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger.<span class="me1">debug</span><span class="br0">&#40;</span> <span class="st0">'línea 1'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger.<span class="me1">debug</span><span class="br0">&#40;</span> <span class="st0">'línea 2'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger.<span class="me1">enable</span><span class="br0">&#40;</span> <span class="kw2">true</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger.<span class="me1">debug</span><span class="br0">&#40;</span> <span class="st0">'línea 3'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="kw1">var</span> logger2 <span class="sy0">=</span> $log.<span class="me1">getLogger</span><span class="br0">&#40;</span> <span class="st0">'App'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger2.<span class="me1">debug</span><span class="br0">&#40;</span> <span class="st0">'otra línea'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
logger2.<span class="me1">debug</span><span class="br0">&#40;</span> <span class="st0">'una línea más'</span> <span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>Salida:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="text"><pre class="de1">[0] -- 12/3/2016 16:02:00 -- [MainController]:0&gt;  línea 3
[1] -- 12/3/2016 16:02:00 -- [App]:0&gt;  otra línea
[2] -- 12/3/2016 16:02:00 -- [App]:1&gt;  una línea más</pre></div></div></div></div></div></div></div>


<p>Los servicios en <strong>AngularJS</strong> se pueden mejorar de dos maneras: Usando <em>decorators</em> o <em>providers</em>.</p>
<p>La ventaja de usar un <em>decorator</em> es que sólo necesitas declararlo dentro del módulo de tu aplicación o incluir el módulo dónde está declarado como dependencia, para que entonces se decore el servicio deseado.</p>
<p>El código presentado a continuación utiliza un <em>decorator</em>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="javascript"><pre class="de1"><span class="br0">&#40;</span> <span class="kw1">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="st0">'use strict'</span><span class="sy0">;</span>
&nbsp;
  <span class="co1">// Asume que el módulo de tu aplicación es llamado &quot;myApp&quot;</span>
  <span class="co1">// En este módulo se define el decorador</span>
  angular.<span class="me1">module</span><span class="br0">&#40;</span> <span class="st0">'myApp'</span> <span class="br0">&#41;</span>.<span class="me1">decorator</span><span class="br0">&#40;</span> <span class="st0">'$log'</span><span class="sy0">,</span> logDecorator <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  <span class="co1">// La función &quot;logDecorator&quot; recibirá el servicio a decorar como</span>
  <span class="co1">// el parámetro $delegate, en este caso $delegate == $log</span>
  <span class="kw1">function</span> logDecorator<span class="br0">&#40;</span> $delegate <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp;
    <span class="co1">// Contador general</span>
    <span class="kw1">var</span> n <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span>
&nbsp;
    <span class="co1">// El nuevo logger que imprime información básica</span>
    <span class="kw1">var</span> basicLogger <span class="sy0">=</span> <span class="br0">&#123;</span>
      log<span class="sy0">:</span> basicDecoration<span class="br0">&#40;</span> $delegate.<span class="me1">log</span> <span class="br0">&#41;</span><span class="sy0">,</span>
      debug<span class="sy0">:</span> basicDecoration<span class="br0">&#40;</span> $delegate.<span class="me1">debug</span> <span class="br0">&#41;</span><span class="sy0">,</span>
      info<span class="sy0">:</span> basicDecoration<span class="br0">&#40;</span> $delegate.<span class="me1">info</span> <span class="br0">&#41;</span><span class="sy0">,</span>
      warn<span class="sy0">:</span>basicDecoration<span class="br0">&#40;</span> $delegate.<span class="me1">warn</span> <span class="br0">&#41;</span><span class="sy0">,</span>
      error<span class="sy0">:</span> basicDecoration<span class="br0">&#40;</span> $delegate.<span class="me1">error</span> <span class="br0">&#41;</span><span class="sy0">,</span>
      getLogger<span class="sy0">:</span> getLogger<span class="sy0">,</span>
      enabledContexts<span class="sy0">:</span> <span class="br0">&#123;</span><span class="br0">&#125;</span><span class="sy0">,</span>
      counter<span class="sy0">:</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
    <span class="br0">&#125;</span><span class="sy0">;</span>
&nbsp;
    <span class="co1">// Esta función regresa el servicio de log básico mejorado</span>
    <span class="kw1">return</span> basicLogger<span class="sy0">;</span>
&nbsp;
&nbsp;
    <span class="co1">// La decoración básica incluye un contador, fecha y hora al inicio</span>
    <span class="kw1">function</span> basicDecoration<span class="br0">&#40;</span> loggingFunction <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="kw1">return</span> <span class="kw1">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span class="kw1">var</span> date <span class="sy0">=</span> <span class="kw1">new</span> <span class="kw4">Date</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="kw1">var</span> args <span class="sy0">=</span> <span class="kw4">Array</span>.<span class="kw1">prototype</span>.<span class="me1">slice</span>.<span class="me1">call</span><span class="br0">&#40;</span> arguments <span class="br0">&#41;</span><span class="sy0">;</span>
        args.<span class="me1">unshift</span><span class="br0">&#40;</span> <span class="st0">'['</span> <span class="sy0">+</span> n<span class="sy0">++</span> <span class="sy0">+</span> <span class="st0">'] -- '</span> <span class="sy0">+</span> date.<span class="me1">toLocaleString</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy0">;</span>
        loggingFunction.<span class="me1">apply</span><span class="br0">&#40;</span> <span class="kw2">null</span><span class="sy0">,</span> args <span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="co1">// La decoración contextual incluye info del contexto y un contador</span>
    <span class="kw1">function</span> contextDecoration<span class="br0">&#40;</span> loggingFunction<span class="sy0">,</span> context <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="kw1">return</span> <span class="kw1">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span class="kw1">var</span> enabled <span class="sy0">=</span> basicLogger.<span class="me1">enabledContexts</span><span class="br0">&#91;</span>context<span class="br0">&#93;</span><span class="sy0">;</span>
        <span class="kw1">if</span><span class="br0">&#40;</span> enabled <span class="sy0">||</span> enabled <span class="sy0">===</span> <span class="kw2">undefined</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span>
          <span class="kw1">var</span> args <span class="sy0">=</span> <span class="kw4">Array</span>.<span class="kw1">prototype</span>.<span class="me1">slice</span>.<span class="me1">call</span><span class="br0">&#40;</span> arguments <span class="br0">&#41;</span><span class="sy0">;</span>
          <span class="kw1">var</span> contextInfo <span class="sy0">=</span> <span class="st0">'-- ['</span> <span class="sy0">+</span> context <span class="sy0">+</span> <span class="st0">':'</span><span class="sy0">;</span>
          <span class="kw1">var</span> counterInfo <span class="sy0">=</span> basicLogger.<span class="me1">counter</span><span class="br0">&#91;</span>context<span class="br0">&#93;</span><span class="sy0">++</span> <span class="sy0">+</span> <span class="st0">'] &gt;&gt; '</span><span class="sy0">;</span>
          args.<span class="me1">unshift</span><span class="br0">&#40;</span> contextInfo <span class="sy0">+</span> counterInfo <span class="br0">&#41;</span><span class="sy0">;</span>
          loggingFunction.<span class="me1">apply</span><span class="br0">&#40;</span> <span class="kw2">null</span><span class="sy0">,</span> args <span class="br0">&#41;</span><span class="sy0">;</span>
        <span class="br0">&#125;</span>
      <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="co1">// Activa o desactiva el logging en un contexto determinado</span>
    <span class="kw1">function</span> enable<span class="br0">&#40;</span> context <span class="br0">&#41;</span> <span class="br0">&#123;</span>
      <span class="kw1">return</span> <span class="kw1">function</span><span class="br0">&#40;</span> enable <span class="br0">&#41;</span> <span class="br0">&#123;</span>
        basicLogger.<span class="me1">enabledContexts</span><span class="br0">&#91;</span>context<span class="br0">&#93;</span> <span class="sy0">=</span> enable<span class="sy0">;</span>
      <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="co1">// Regresa un logger para un contexto determinado</span>
    <span class="kw1">function</span> getLogger<span class="br0">&#40;</span> context <span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp;
      <span class="co1">// Contador contextual</span>
      basicLogger.<span class="me1">counter</span><span class="br0">&#91;</span>context<span class="br0">&#93;</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span>
&nbsp;
      <span class="co1">// La nueva instancia de logger con información del contexto</span>
      <span class="kw1">var</span> contextLogger <span class="sy0">=</span> <span class="br0">&#123;</span>
        log<span class="sy0">:</span> contextDecoration<span class="br0">&#40;</span> basicLogger.<span class="me1">log</span><span class="sy0">,</span> context <span class="br0">&#41;</span><span class="sy0">,</span>
        debug<span class="sy0">:</span> contextDecoration<span class="br0">&#40;</span> basicLogger.<span class="me1">debug</span><span class="sy0">,</span> context <span class="br0">&#41;</span><span class="sy0">,</span>
        info<span class="sy0">:</span> contextDecoration<span class="br0">&#40;</span> basicLogger.<span class="me1">info</span><span class="sy0">,</span> context <span class="br0">&#41;</span><span class="sy0">,</span>
        warn<span class="sy0">:</span> contextDecoration<span class="br0">&#40;</span> basicLogger.<span class="me1">warn</span><span class="sy0">,</span> context <span class="br0">&#41;</span><span class="sy0">,</span>
        error<span class="sy0">:</span> contextDecoration<span class="br0">&#40;</span> basicLogger.<span class="me1">error</span><span class="sy0">,</span> context <span class="br0">&#41;</span><span class="sy0">,</span>
        enable<span class="sy0">:</span> enable<span class="br0">&#40;</span> context <span class="br0">&#41;</span>
      <span class="br0">&#125;</span><span class="sy0">;</span>
&nbsp;
      <span class="co1">// Esta función regresa el servicio de log contextualizado</span>
      <span class="kw1">return</span> contextLogger<span class="sy0">;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span> <span class="br0">&#41;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div></div></div></div></div></div>


<p>Una recomendación es que siempre utilices el servicio de AngularJS <strong>$log</strong> en vez del <strong>console.log</strong>, de esta manera siempre podrás desactivar todo el <em>logging</em> desde el bloque de configuración de tu aplicación con algo como esto:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="javascript"><pre class="de1">angular.<span class="me1">module</span><span class="br0">&#40;</span> <span class="st0">'myApp'</span><span class="sy0">,</span> <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#41;</span>.<span class="me1">config</span><span class="br0">&#40;</span> config <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="kw1">function</span> config<span class="br0">&#40;</span> $logProvider <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  $logProvider.<span class="me1">debugEnabled</span><span class="br0">&#40;</span> <span class="kw2">false</span> <span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>Con este nuevo <strong>logger</strong> también puedes mandar a consola toda actividad en tus controladores, directivas, servicios, etc., y si la información que aparece es demasiada, puedes desactivar los contextos que gustes desde el bloque de ejecución de tu aplicación.</p>
<p>Digamos que tienes un controlador llamado <strong>MainController</strong>, y en él inicializas un <strong>logger</strong> con contexto &#8220;MainController&#8221;. Para desactivar toda la salida a consola generada por ese controlador, puedes hacer algo así:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="javascript"><pre class="de1">angular.<span class="me1">module</span><span class="br0">&#40;</span> <span class="st0">'myApp'</span><span class="sy0">,</span> <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="br0">&#41;</span>.<span class="me1">config</span><span class="br0">&#40;</span> config <span class="br0">&#41;</span>.<span class="me1">run</span><span class="br0">&#40;</span> run <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="kw1">function</span> config<span class="br0">&#40;</span> $logProvider <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  $logProvider.<span class="me1">debugEnabled</span><span class="br0">&#40;</span> <span class="kw2">true</span> <span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw1">function</span> run<span class="br0">&#40;</span> $log <span class="br0">&#41;</span> <span class="br0">&#123;</span>
  <span class="kw1">var</span> logger <span class="sy0">=</span> $log.<span class="me1">getLogger</span><span class="br0">&#40;</span> <span class="st0">'MainController'</span> <span class="br0">&#41;</span><span class="sy0">;</span>
  logger.<span class="me1">enable</span><span class="br0">&#40;</span> <span class="kw2">false</span> <span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div></div></div></div></div></div>


<p>La idea es que en cada componente de tu aplicación tengas un <em>logger</em> y el contexto sea el nombre del componente.</p>
<h2>Referencias</h2>
<p><a href="http://solutionoptimist.com/2013/10/07/enhance-angularjs-logging-using-decorators/">Enhancing AngularJS Logging using Decorators</a><br />
<a href="http://www.bennybottema.com/2013/12/23/enhance-logging-in-angularjs-the-simple-way/">Enhancing $log in AngularJs the simple way</a></p>
]]></content:encoded>
			<wfw:commentRss>http://lobotuerto.com/blog/2016/03/12/mejorando-el-log-de-angularjs-con-decorators/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<post-id xmlns="com-wordpress:feed-additions:1">6562</post-id>	</item>
		<item>
		<title>Error al actualizar Google Chrome en Ubuntu</title>
		<link>http://lobotuerto.com/blog/2016/03/10/error-al-actualizar-google-chrome-en-ubuntu/</link>
		<comments>http://lobotuerto.com/blog/2016/03/10/error-al-actualizar-google-chrome-en-ubuntu/#comments</comments>
		<pubDate>Thu, 10 Mar 2016 16:13:29 +0000</pubDate>
		<dc:creator><![CDATA[lobo_tuerto]]></dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[apt-get]]></category>
		<category><![CDATA[google chrome]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[update]]></category>

		<guid isPermaLink="false">http://lobotuerto.com/blog/?p=6557</guid>
		<description><![CDATA[Si al tratar de hacer un apt-get update te aparece un error de: entrada incorrecta en «sources.list» o fichero mal formado y menciona los sources para Google Chrome: W: Fallo al obtener http://dl.google.com/linux/chrome/deb/dists/stable/Release No se pudo encontrar la entrada esperada «main/binary-i386/Packages» en el archivo «Release» (entrada incorrecta en «sources.list» o fichero mal formado) &#160; W: &#8230; <p class="link-more"><a href="http://lobotuerto.com/blog/2016/03/10/error-al-actualizar-google-chrome-en-ubuntu/" class="more-link">Continuar leyendo<span class="screen-reader-text"> "Error al actualizar Google Chrome en Ubuntu"</span></a></p>]]></description>
				<content:encoded><![CDATA[<p>Si al tratar de hacer un <strong>apt-get update</strong> te aparece un error de: <em>entrada incorrecta en «sources.list» o fichero mal formado</em> y menciona los <em>sources</em> para <strong>Google Chrome</strong>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="text"><pre class="de1">W: Fallo al obtener http://dl.google.com/linux/chrome/deb/dists/stable/Release  No se pudo encontrar la entrada esperada «main/binary-i386/Packages» en el archivo «Release» (entrada incorrecta en «sources.list» o fichero mal formado)
&nbsp;
W: Fallo al obtener http://archive.ubuntu.com/ubuntu/dists/wily-security/universe/source/Sources  La suma hash difiere
&nbsp;
W: Fallo al obtener http://archive.ubuntu.com/ubuntu/dists/wily-security/universe/binary-amd64/Packages  La suma hash difiere
&nbsp;
W: Fallo al obtener http://archive.ubuntu.com/ubuntu/dists/wily-security/universe/binary-i386/Packages  La suma hash difiere
&nbsp;
E: No se han podido descargar algunos archivos de índice, se han omitido, o se han utilizado unos antiguos en su lugar.</pre></div></div></div></div></div></div></div>


<p>Debes modificar tu archivo <strong>/etc/apt/sources.list.d/google-chrome.list</strong>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1"><span class="kw2">sudo</span> gedit <span class="sy0">/</span>etc<span class="sy0">/</span>apt<span class="sy0">/</span>sources.list.d<span class="sy0">/</span>google-chrome.list</pre></div></div></div></div></div></div></div>


<p>Y cambiar la línea:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="text"><pre class="de1">deb http://dl.google.com/linux/chrome/deb/ stable main</pre></div></div></div></div></div></div></div>


<p>Por esta:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="text"><pre class="de1">deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main</pre></div></div></div></div></div></div></div>


<p>Listo, dale:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1"><span class="kw2">sudo</span> <span class="kw2">apt-get update</span></pre></div></div></div></div></div></div></div>


<h2>Referencia</h2>
<p><a href="http://www.omgubuntu.co.uk/2016/03/fix-failed-to-fetch-google-chrome-apt-error-ubuntu">How To Fix The (Annoying) ‘Failed to Fetch’ Chrome apt Error</a></p>
]]></content:encoded>
			<wfw:commentRss>http://lobotuerto.com/blog/2016/03/10/error-al-actualizar-google-chrome-en-ubuntu/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	<post-id xmlns="com-wordpress:feed-additions:1">6557</post-id>	</item>
		<item>
		<title>A nivel nacional y estado por estado, la pobreza en México</title>
		<link>http://lobotuerto.com/blog/2015/08/28/a-nivel-nacional-y-estado-por-estado-la-pobreza-en-mexico/</link>
		<comments>http://lobotuerto.com/blog/2015/08/28/a-nivel-nacional-y-estado-por-estado-la-pobreza-en-mexico/#respond</comments>
		<pubDate>Fri, 28 Aug 2015 14:04:05 +0000</pubDate>
		<dc:creator><![CDATA[lobo_tuerto]]></dc:creator>
				<category><![CDATA[Data visualization]]></category>
		<category><![CDATA[Visualización de datos]]></category>

		<guid isPermaLink="false">http://lobotuerto.com/blog/?p=6520</guid>
		<description><![CDATA[Visualización en Acción Ciudadana Frente a la Pobreza Artículo en Animal Político Da clic sobre algún rubro que desees explorar y/o sobre algún Estado para conocer datos particulares.]]></description>
				<content:encoded><![CDATA[<ul>
<li><a href="http://frentealapobreza.mx/pobreza-2014/">Visualización en Acción Ciudadana Frente a la Pobreza</a></li>
<li><a href="http://www.animalpolitico.com/2015/08/estado-a-estado-la-situacion-de-pobreza-de-mexico/">Artículo en Animal Político</a></li>
</ul>
<p>Da clic sobre algún rubro que desees explorar y/o sobre algún Estado para conocer datos particulares.<br />
<iframe src="http://frentealapobreza.mx/pobreza2014" style="width: 100%; height: 1650px"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://lobotuerto.com/blog/2015/08/28/a-nivel-nacional-y-estado-por-estado-la-pobreza-en-mexico/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<post-id xmlns="com-wordpress:feed-additions:1">6520</post-id>	</item>
		<item>
		<title>Cómo arreglar el doble ícono de Google Chrome en elementary OS</title>
		<link>http://lobotuerto.com/blog/2015/04/19/como-arreglar-el-doble-icono-de-google-chrome-en-elementary-os/</link>
		<comments>http://lobotuerto.com/blog/2015/04/19/como-arreglar-el-doble-icono-de-google-chrome-en-elementary-os/#respond</comments>
		<pubDate>Sun, 19 Apr 2015 19:21:05 +0000</pubDate>
		<dc:creator><![CDATA[lobo_tuerto]]></dc:creator>
				<category><![CDATA[guías]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[chrome]]></category>
		<category><![CDATA[doble ícono]]></category>
		<category><![CDATA[elementary os]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://lobotuerto.com/blog/?p=6475</guid>
		<description><![CDATA[Al abrir Google Chrome aparece dos veces el ícono en el dock. Para corregirlo, abre una terminal y teclea esto: sudo nano /usr/share/applications/google-chrome.desktop Inserta StartupWMClass=Google-chrome-stable bajo cada una de las tres secciones siguientes: &#91;Desktop Entry&#93; StartupWMClass=Google-chrome-stable ... &#160; &#91;NewWindow Shortcut Group&#93; StartupWMClass=Google-chrome-stable ... &#160; &#91;NewIncognito Shortcut Group&#93; StartupWMClass=Google-chrome-stable ...]]></description>
				<content:encoded><![CDATA[<p>Al abrir <strong>Google Chrome</strong> aparece dos veces el ícono en el <em>dock</em>.</p>
<p>Para corregirlo, abre una terminal y teclea esto:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1"><span class="kw2">sudo</span> <span class="kw2">nano</span> <span class="sy0">/</span>usr<span class="sy0">/</span>share<span class="sy0">/</span>applications<span class="sy0">/</span>google-chrome.desktop</pre></div></div></div></div></div></div></div>


<p>Inserta <em>StartupWMClass=Google-chrome-stable</em> bajo cada una de las tres secciones siguientes:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1"><span class="br0">&#91;</span>Desktop Entry<span class="br0">&#93;</span>
<span class="re2">StartupWMClass</span>=Google-chrome-stable
...
&nbsp;
<span class="br0">&#91;</span>NewWindow Shortcut Group<span class="br0">&#93;</span>
<span class="re2">StartupWMClass</span>=Google-chrome-stable
...
&nbsp;
<span class="br0">&#91;</span>NewIncognito Shortcut Group<span class="br0">&#93;</span>
<span class="re2">StartupWMClass</span>=Google-chrome-stable
...</pre></div></div></div></div></div></div></div>


]]></content:encoded>
			<wfw:commentRss>http://lobotuerto.com/blog/2015/04/19/como-arreglar-el-doble-icono-de-google-chrome-en-elementary-os/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<post-id xmlns="com-wordpress:feed-additions:1">6475</post-id>	</item>
		<item>
		<title>Mi nuevo Ubuntu, o mejor dicho, elementary OS :)</title>
		<link>http://lobotuerto.com/blog/2015/04/19/mi-nuevo-ubuntu-o-mejor-dicho-elementary-os/</link>
		<comments>http://lobotuerto.com/blog/2015/04/19/mi-nuevo-ubuntu-o-mejor-dicho-elementary-os/#comments</comments>
		<pubDate>Sun, 19 Apr 2015 16:07:53 +0000</pubDate>
		<dc:creator><![CDATA[lobo_tuerto]]></dc:creator>
				<category><![CDATA[Sin categoría]]></category>

		<guid isPermaLink="false">http://lobotuerto.com/blog/?p=6468</guid>
		<description><![CDATA[Si eres usuario de Ubuntu, o alguna otra distribución basada en él, te recomiendo pruebes elementary OS. Quedarás gratamente sorprendido. 🙂]]></description>
				<content:encoded><![CDATA[<p>Si eres usuario de <strong>Ubuntu</strong>, o alguna otra distribución basada en él, te recomiendo pruebes <a href="https://elementary.io/" title="elementary OS">elementary OS</a>. Quedarás gratamente sorprendido. <img src="https://s.w.org/images/core/emoji/2.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p><a href="http://lobotuerto.com/blog/wp-content/uploads/2015/04/Captura-de-pantalla-de-2015-04-19-1102351.png"><img src="http://lobotuerto.com/blog/wp-content/uploads/2015/04/Captura-de-pantalla-de-2015-04-19-1102351-1024x640.png" alt="Captura de pantalla de 2015-04-19 11:02:35" width="720" height="450" class="aligncenter size-large wp-image-6470" srcset="http://lobotuerto.com/blog/wp-content/uploads/2015/04/Captura-de-pantalla-de-2015-04-19-1102351-1024x640.png 1024w, http://lobotuerto.com/blog/wp-content/uploads/2015/04/Captura-de-pantalla-de-2015-04-19-1102351-300x188.png 300w" sizes="(max-width: 720px) 100vw, 720px" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://lobotuerto.com/blog/2015/04/19/mi-nuevo-ubuntu-o-mejor-dicho-elementary-os/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	<post-id xmlns="com-wordpress:feed-additions:1">6468</post-id>	</item>
		<item>
		<title>Configuración de una aplicación Rails 4.2 con MongoDB para una JSON API</title>
		<link>http://lobotuerto.com/blog/2015/04/01/configuracion-de-una-aplicacion-rails-con-mongodb-para-una-json-api/</link>
		<comments>http://lobotuerto.com/blog/2015/04/01/configuracion-de-una-aplicacion-rails-con-mongodb-para-una-json-api/#respond</comments>
		<pubDate>Wed, 01 Apr 2015 16:40:23 +0000</pubDate>
		<dc:creator><![CDATA[lobo_tuerto]]></dc:creator>
				<category><![CDATA[guías]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[tutoriales]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[bdd]]></category>
		<category><![CDATA[configuracion]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[minitest]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[mongoid]]></category>
		<category><![CDATA[preparación]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[tdd]]></category>

		<guid isPermaLink="false">http://lobotuerto.com/blog/?p=6312</guid>
		<description><![CDATA[En esta guía se explica cómo crear y configurar una aplicación Rails con MongoDB, de tal manera que funcione como una JSON API, es decir, puro back end. Una aplicación de este tipo se da muy bien para después conectarla con un cliente SPA (Single Page Application), digamos en AngularJS o para emplearla con una &#8230; <p class="link-more"><a href="http://lobotuerto.com/blog/2015/04/01/configuracion-de-una-aplicacion-rails-con-mongodb-para-una-json-api/" class="more-link">Continuar leyendo<span class="screen-reader-text"> "Configuración de una aplicación Rails 4.2 con MongoDB para una JSON API"</span></a></p>]]></description>
				<content:encoded><![CDATA[<p>En esta guía se explica cómo crear y configurar una aplicación <a href="http://rubyonrails.org/" title="Ruby on Rails">Rails</a> con <a href="https://www.mongodb.org/" title="MongoDB">MongoDB</a>, de tal manera que funcione como una <strong>JSON API</strong>, es decir, puro <em><a href="http://en.wikipedia.org/wiki/Front_and_back_ends" title="Front and back ends">back end</a></em>.</p>
<p>Una aplicación de este tipo se da muy bien para después conectarla con un cliente <a href="http://en.wikipedia.org/wiki/Single-page_application" title="Single-page application">SPA</a> (<em>Single Page Application</em>), digamos en <a href="https://angularjs.org/" title="AngularJS">AngularJS</a> o para emplearla con una aplicación móvil hecha con <a href="http://ionicframework.com/" title="Ionic">Ionic</a>, por ejemplo.</p>
<p>Se asume familiaridad con <strong>Rails</strong>, <strong>git</strong> y los <a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes" title="List of HTTP status codes">códigos de estado HTTP</a>.</p>
<h1>Preliminares</h1>
<ul>
<li><a href="http://lobotuerto.com/blog/2012/10/07/como-instalar-ruby-con-rbenv-en-ubuntu/" title="Cómo instalar Ruby con rbenv en Ubuntu">Instala Ruby</a></li>
<li><a href="http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/" title="Install MongoDB on Ubuntu">Instala MongoDB</a></li>
</ul>
<h1>Commit inicial</h1>
<p>Para generar el proyecto y hacer el primer <em>commit</em>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rails new json_api <span class="re5">--skip-active-record</span>
<span class="kw3">cd</span> json_api
<span class="kw2">git init</span>
<span class="kw2">git add</span> .
<span class="kw2">git</span> ci <span class="re5">-m</span> <span class="st0">&quot;Commit inicial.&quot;</span></pre></div></div></div></div></div></div></div>


<p>La opción de <strong>&#8211;skip-active-record</strong> desactiva <strong>ActiveRecord</strong> porque usaremos <strong>MongoDB</strong> con <strong>Mongoid</strong> en lugar de una base de datos relacional como <strong>PostgreSQL</strong> o <strong>MySQL</strong>.</p>
<h1>Configuración inicial</h1>
<p>Agrega estas gemas a tu <strong>Gemfile</strong>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">group <span class="re3">:development</span>, <span class="re3">:test</span> <span class="kw1">do</span>
  ...
  <span class="co1"># Framework para pruebas</span>
  gem <span class="st0">'minitest-rails'</span>
  <span class="co1"># Para generar objetos de prueba</span>
  gem <span class="st0">'fabrication'</span>
  <span class="co1"># Para generar datos de prueba</span>
  gem <span class="st0">'faker'</span>
<span class="kw1">end</span>
&nbsp;
<span class="co1"># Para usar MongoDB a través de Mongoid</span>
gem <span class="st0">'mongoid'</span>
<span class="co1"># Para usar respond_with en los controladores</span>
gem <span class="st0">'responders'</span>
<span class="co1"># Para usar ActiveModel#has_secure_password</span>
gem <span class="st0">'bcrypt'</span></pre></div></div></div></div></div></div></div>


<p>Después en la terminal:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">bundle
rails g mongoid:config
rails g minitest:install</pre></div></div></div></div></div></div></div>


<p>Con esto se instalan las gemas que hagan falta, después se generan los archivos de configuración para <strong>Mongoid</strong> y <strong>Minitest</strong>. No es necesario correr el generador para los <em>responders</em>.</p>
<p>Al ejecutar el generador de <strong>Minitest</strong>, te va a preguntar si debe sobreescribir el archivo <strong>test_helper.rb</strong>, contesta sí.</p>
<p>En el archivo <strong>config/mongoid.yml</strong>, quita el comentario de la línea que aparece a continuación y cambia el valor a <em>false</em>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="co1"># raise_not_found_error: true</span>
raise_not_found_error: <span class="kw2">false</span></pre></div></div></div></div></div></div></div>


<p>No queremos que <strong>Mongoid</strong> levante una excepción toda vez que no encuentre un documento.</p>
<p>Es deseable tener más control sobre cuándo se lanza una excepción, de esta forma, cuando se busca un usuario para autenticación y no existe, en vez de un código de error <strong>404</strong> (<em>Not Found</em>) podemos mandar un <strong>401</strong> (<em>Unauthorized</em>).</p>
<p>Agrega este contenido al archivo <strong>config/application.rb</strong>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">config.<span class="me1">generators</span> <span class="kw1">do</span> <span class="sy0">|</span>g<span class="sy0">|</span>
  <span class="co1"># Framework de pruebas estilo BDD</span>
  g.<span class="me1">test_framework</span> <span class="re3">:minitest</span>, spec: <span class="kw2">true</span>, fixture: <span class="kw2">true</span>, fixture_replacement: <span class="re3">:fabrication</span>
&nbsp;
  <span class="co1"># Estamos haciendo una API, no queremos assets, helpers, tampoco views</span>
  g.<span class="me1">assets</span> <span class="kw2">false</span>
  g.<span class="me1">helper</span> <span class="kw2">false</span>
  g.<span class="me1">template_engine</span> <span class="kw2">nil</span>
<span class="kw1">end</span>
&nbsp;
<span class="co1"># Para manejar la presentación de errores 404 y 500 como JSON</span>
config.<span class="me1">exceptions_app</span> = <span class="kw2">self</span>.<span class="me1">routes</span></pre></div></div></div></div></div></div></div>


<p>En el archivo <strong>test/test_helper.rb</strong>, comenta las siguientes líneas:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="co1"># ActiveRecord::Migration.check_pending!</span>
<span class="co1"># fixtures :all</span></pre></div></div></div></div></div></div></div>


<p>No tenemos disponible <strong>ActiveRecord</strong>, si no se comentan esas líneas al tratar de ejecutar las pruebas se lanzará una excepción.</p>
<p>En el archivo <strong>config/initializers/inflections.rb</strong> agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">ActiveSupport::<span class="kw4">Inflector</span>.<span class="me1">inflections</span><span class="br0">&#40;</span> <span class="re3">:en</span> <span class="br0">&#41;</span> <span class="kw1">do</span> <span class="sy0">|</span>inflect<span class="sy0">|</span>
  inflect.<span class="me1">acronym</span> <span class="st0">'API'</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Esto permite que al generar los controladores se utilice <strong>API</strong> como nombre del módulo contenedor en lugar de <strong>Api</strong>.</p>
<h1>Configuración de rutas y del controlador principal de la aplicación</h1>
<p>En el archivo <strong>config/routes.rb</strong> agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">match <span class="st0">'/404'</span> <span class="sy0">=&gt;</span> <span class="st0">'application#not_found'</span>, via: <span class="br0">&#91;</span><span class="re3">:get</span>, <span class="re3">:post</span>, <span class="re3">:put</span>, <span class="re3">:patch</span>, <span class="re3">:delete</span><span class="br0">&#93;</span>
match <span class="st0">'/500'</span> <span class="sy0">=&gt;</span> <span class="st0">'application#exception'</span>, via: <span class="br0">&#91;</span><span class="re3">:get</span>, <span class="re3">:post</span>, <span class="re3">:put</span>, <span class="re3">:patch</span>, <span class="re3">:delete</span><span class="br0">&#93;</span></pre></div></div></div></div></div></div></div>


<p>Esto permite personalizar las respuestas de error cuando no se encuentra alguna ruta o cuando se tiene algún error en la aplicación.</p>
<p>Por defecto, en estos casos lo que se devuelve es HTML (y el código de estado HTTP adecuado), pero estamos interesados en siempre entregar JSON al cliente.</p>
<p>En el archivo <strong>app/controllers/application_controller.rb</strong> cambia <strong>:exception</strong> por <strong>:null_session</strong> y agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">protect_from_forgery with: <span class="re3">:null_session</span>
&nbsp;
<span class="co1"># Estos métodos se llaman desde las rutas</span>
<span class="kw1">def</span> not_found
  response = http_error<span class="br0">&#40;</span> <span class="br0">&#123;</span> status: <span class="st0">'404'</span>, message: <span class="st0">'Not Found'</span> <span class="br0">&#125;</span> <span class="br0">&#41;</span>
  render json: response, status: <span class="re3">:not_found</span>
<span class="kw1">end</span>
&nbsp;
<span class="kw1">def</span> exception
  response = http_error<span class="br0">&#40;</span> <span class="br0">&#123;</span> status: <span class="st0">'500'</span>, message: <span class="st0">'Internal Server Error'</span> <span class="br0">&#125;</span> <span class="br0">&#41;</span>
  render json: response, status: <span class="re3">:internal_server_error</span>
<span class="kw1">end</span>
&nbsp;
&nbsp;
private
<span class="co1"># Método de utilería</span>
<span class="kw1">def</span> http_error<span class="br0">&#40;</span> error <span class="br0">&#41;</span>
  <span class="br0">&#123;</span> error: <span class="br0">&#123;</span> http: error <span class="br0">&#125;</span> <span class="br0">&#125;</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>La línea de <em>protect_from_forgery_with</em> indica el tipo de protección que se utilizará como medida de prevención contra un ataque de tipo <a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet" title="Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet">CSRF</a>.</p>
<p>Cuando es <strong>:exception</strong> se lanza una excepción ante cualquier petición POST, PUT, PATCH o DELETE si no viene acompañada de un token especial que <strong>Rails</strong> normalmente inserta en las vistas. Siendo esta una aplicación que va a ser utilizada como <strong>API</strong> no cuenta con ellas.</p>
<p>De la documentación: <a href="http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html" title="ActionController::RequestForgeryProtection::ClassMethods">ActionController::RequestForgeryProtection::ClassMethods</a></p>
<blockquote><p>Turn on request forgery protection. Bear in mind that GET and HEAD requests are not checked.</p></blockquote>
<p>Con <strong>:null_session</strong> se indica que no habrá estado del lado del servidor, por tanto, no existe una sesión que mantega el estado de <em>conectado</em> dentro del sistema. La autenticación se logra por medio de un token especial que se enviará desde el cliente en la cabecera de la petición. Más adelante veremos cómo.</p>
<h2>Otros errores que sería bueno atrapar</h2>
<p>Igual, en el archivo <strong>app/controllers/application_controller.rb</strong> agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="co1"># Para cuando lancemos la excepción de documento no encontrado en MongoDB</span>
rescue_from <span class="re2">Mongoid::Errors::DocumentNotFound</span>, with: <span class="re3">:document_not_found</span>
<span class="co1"># Para cuando el tipo de contenido solicitado no sea application/json</span>
rescue_from <span class="re2">ActionController::UnknownFormat</span>, with: <span class="re3">:not_acceptable</span>
<span class="co1"># Para cuando hagan falta parámetros requeridos en algún modelo</span>
rescue_from <span class="re2">ActionController::ParameterMissing</span>, with: <span class="re3">:unprocessable_entity</span>
&nbsp;
<span class="kw1">def</span> document_not_found
  response = http_error<span class="br0">&#40;</span> <span class="br0">&#123;</span> status: <span class="st0">'404'</span>, message: <span class="st0">'Document Not Found'</span> <span class="br0">&#125;</span> <span class="br0">&#41;</span>
  render json: response, status: <span class="re3">:not_found</span>
<span class="kw1">end</span>
&nbsp;
<span class="kw1">def</span> not_acceptable
  response = http_error<span class="br0">&#40;</span> <span class="br0">&#123;</span> status: <span class="st0">'406'</span>, message: <span class="st0">'Not Acceptable'</span> <span class="br0">&#125;</span> <span class="br0">&#41;</span>
  render json: response, status: <span class="re3">:not_acceptable</span>
<span class="kw1">end</span>
&nbsp;
<span class="kw1">def</span> unprocessable_entity
  response = http_error<span class="br0">&#40;</span> <span class="br0">&#123;</span> status: <span class="st0">'422'</span>, message: <span class="st0">'Unprocessable Entity'</span> <span class="br0">&#125;</span> <span class="br0">&#41;</span>
  render json: response, status: <span class="re3">:unprocessable_entity</span>
<span class="kw1">end</span>
&nbsp;
<span class="kw1">def</span> unauthorized
  response = http_error<span class="br0">&#40;</span> <span class="br0">&#123;</span> status: <span class="st0">'401'</span>, message: <span class="st0">'Unauthorized'</span> <span class="br0">&#125;</span> <span class="br0">&#41;</span>
  render json: response, status: <span class="re3">:unauthorized</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Con la configuración inicial terminada, agrega los cambios al repo:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1"><span class="kw2">git add</span> .
<span class="kw2">git</span> ci <span class="re5">-m</span> <span class="st0">&quot;Configuración inicial.&quot;</span></pre></div></div></div></div></div></div></div>


<h1>Testing</h1>
<h2>TDD vs BDD</h2>
<p>La diferencia entre los dos es el cómo te gusta pensar acerca del modelado de la aplicación.</p>
<p>El TDD utiliza el <strong>es</strong> (<em>assert</em>, afirma), el BDD usa el <strong>debe</strong> (<em>must</em>, debe). Básicamente es una cuestión de <strong>es</strong> vs <strong>debe</strong> ser.</p>
<h2>Probemos primero con un poco de BDD</h2>
<h3>Genera tu primer controlador</h3>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rails g controller API::Users</pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>test/controllers/api/users_controller_test.rb</strong> y cambia el test de ejemplo por:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">it <span class="st0">&quot;#index debe ser exitoso&quot;</span> <span class="kw1">do</span>
  get <span class="re3">:index</span>
  response.<span class="me1">status</span>.<span class="me1">must_equal</span> <span class="nu0">200</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>config/routes.rb</strong> para agregar el recurso:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">namespace <span class="re3">:api</span> <span class="kw1">do</span>
  resources <span class="re3">:users</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>app/controllers/api/users_controller.rb</strong> y agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw1">def</span> index
  render json: <span class="br0">&#123;</span><span class="br0">&#125;</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p><img src="https://s.w.org/images/core/emoji/2.3/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Esta fue una muestra de un proceso muy básico de BDD para un controlador.</p>
<h3>Genera tu primer modelo</h3>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rails g model User name:string email:string password_digest:string</pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Abre el archivo <strong>test/models/user_test.rb</strong> y verás:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw3">require</span> <span class="st0">'test_helper'</span>
&nbsp;
describe User <span class="kw1">do</span>
  let<span class="br0">&#40;</span> <span class="re3">:user</span> <span class="br0">&#41;</span> <span class="br0">&#123;</span> User.<span class="me1">new</span> <span class="br0">&#125;</span>
&nbsp;
  it <span class="st0">&quot;must be valid&quot;</span> <span class="kw1">do</span>
    user.<span class="me1">must_be</span> <span class="re3">:valid</span>?
  <span class="kw1">end</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Si analizamos un poco la situación y contemplamos nuestro modelo <strong>User</strong>, veremos que el usuario forzosamente necesita al menos un correo. Así, un usuario recién creado debería ser inválido.</p>
<p>Cambia el único test que existe en ese archivo por este otro:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">it <span class="st0">'no debe ser válido'</span> <span class="kw1">do</span>
  user.<span class="me1">wont_be</span> <span class="re3">:valid</span>?
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Abre el archivo <strong>app/models/user.rb</strong> y agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">validates <span class="re3">:email</span>, presence: <span class="kw2">true</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p><img src="https://s.w.org/images/core/emoji/2.3/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Y esta fue una muestra de un proceso muy básico de BDD para un modelo.</p>
<p>A continuación veremos cómo se haría con TDD.</p>
<h2>Probemos ahora con un poco de TDD</h2>
<p>Para que las pruebas se generen al estilo TDD cambia <em>spec</em> a <em>false</em>:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">g.<span class="me1">test_framework</span> <span class="re3">:minitest</span>, spec: <span class="kw2">false</span>, fixture: <span class="kw2">false</span></pre></div></div></div></div></div></div></div>


<h3>Genera tu primer controlador</h3>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rails g controller API::Users</pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>test/controllers/api/users_controller_test.rb</strong> y cambia el test de ejemplo por:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw1">def</span> test_index_action
  get <span class="re3">:index</span>
  assert_response <span class="re3">:success</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p><em>Nota: El nombre de los métodos debe comenzar necesariamente con <strong>test_</strong> para que sean ejecutados durante el proceso de pruebas.</em></p>
<p>El método anterior es equivalente a este:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">test <span class="st0">'index action'</span> <span class="kw1">do</span>
  get <span class="re3">:index</span>
  assert_response <span class="re3">:success</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>config/routes.rb</strong> para agregar el recurso:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">namespace <span class="re3">:api</span> <span class="kw1">do</span>
  resources <span class="re3">:users</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Edita <strong>app/controllers/api/users_controller.rb</strong> y agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw1">def</span> index
  render json: <span class="br0">&#123;</span><span class="br0">&#125;</span>
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p><img src="https://s.w.org/images/core/emoji/2.3/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Esta fue una muestra de un proceso muy básico de TDD para un controlador.</p>
<h3>Genera tu primer modelo</h3>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rails g model User name:string email:string password_digest:string</pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Abre el archivo <strong>test/models/user_test.rb</strong> y verás:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw3">require</span> <span class="st0">'test_helper'</span>
&nbsp;
<span class="kw1">class</span> UserTest <span class="sy0">&lt;</span> <span class="re2">ActiveSupport::TestCase</span>
&nbsp;
  <span class="kw1">def</span> user
    <span class="re1">@user</span> <span class="sy0">||</span>= User.<span class="me1">new</span>
  <span class="kw1">end</span>
&nbsp;
  <span class="kw1">def</span> test_valid
    assert user.<span class="me1">valid</span>?
  <span class="kw1">end</span>
&nbsp;
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Si analizamos un poco la situación y contemplamos nuestro modelo <strong>User</strong>, veremos que el usuario forzosamente necesita al menos un correo. Así, un usuario recién creado debería ser inválido.</p>
<p>Cambia el único test que existe en ese archivo por este otro:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1"><span class="kw1">def</span> test_invalid
  assert_not user.<span class="me1">valid</span>?
<span class="kw1">end</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p>Abre el archivo <strong>app/models/user.rb</strong> y agrega:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="ruby"><pre class="de1">validates <span class="re3">:email</span>, presence: <span class="kw2">true</span></pre></div></div></div></div></div></div></div>


<p>Ejecuta y observa:</p>


<div class="wp-geshi-highlight-wrap5"><div class="wp-geshi-highlight-wrap4"><div class="wp-geshi-highlight-wrap3"><div class="wp-geshi-highlight-wrap2"><div class="wp-geshi-highlight-wrap"><div class="wp-geshi-highlight"><div class="bash"><pre class="de1">rake <span class="kw3">test</span></pre></div></div></div></div></div></div></div>


<p><img src="https://s.w.org/images/core/emoji/2.3/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Y esta fue una muestra de un proceso muy básico de TDD para un modelo.</p>
<p>En lo personal prefiero el BDD, siento que en ese estilo se expresa mejor la intención de lo que quieres programar.</p>
<h1>Finalmente</h1>
<p>Más adelante publicaré una guía acerca de cómo hacer <strong>pruebas de integración</strong> y cómo utilizar <em>fabricators</em> de manera efectiva en las pruebas de modelos y controladores.</p>
<p>Espero esta guía te sea útil.</p>
<h2>Repositorio en github</h2>
<p><a href="https://github.com/lobo-tuerto/rails_json_api" title="Rails + MongoDB JSON API">lobo-tuerto/rails_json_api</a></p>
]]></content:encoded>
			<wfw:commentRss>http://lobotuerto.com/blog/2015/04/01/configuracion-de-una-aplicacion-rails-con-mongodb-para-una-json-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<post-id xmlns="com-wordpress:feed-additions:1">6312</post-id>	</item>
	</channel>
</rss>
