<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ASCIIcasts - Full Episode Feed</title>
    <description>The latest episodes from ASCIIcasts</description>
    <link>http://asciicasts.com/</link>
    <pubDate>Sun, 19 Feb 2012 18:52:27 +0000</pubDate>
    <ttl>1440</ttl>
    <item>
      <title>Spork</title>
      <description>&lt;p&gt; &lt;a href="https://github.com/timcharper/spork"&gt;Spork&lt;/a&gt; es una gema de Ruby que acelera la carga de los tests de nuestras aplicaciones, en este episodio investigaremos c&amp;oacute;mo podemos usar esta gema para hacer que los tests se ejecuten m&amp;aacute;s r&amp;aacute;pido.&lt;/p&gt;

&lt;p&gt;Por lo general cuando ejecutamos la suite de tests de una aplicaci&amp;oacute;n Rails pasan unos segundos antes de que los tests empiecen a ejecutarse.  Podemos medir la duraci&amp;oacute;n de esta pausa con la orden &lt;code&gt;time&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ time rspec .
.........

Finished in 1.98 seconds
9 examples, 0 failures

real	0m11.090s
user	0m9.735s
sys	0m1.306s&lt;/pre&gt;

&lt;p&gt;Aunque RSpec dice que los tests le han llevado s&amp;oacute;lo unos segundos el tiempo transcurrido desde que ejecutamos &lt;code&gt;rspec&lt;/code&gt; y su finalizaci&amp;oacute;n es mucho mayor, unos 11 segundos.  El tiempo extra es el tiempo que se tarda en cargar el c&amp;oacute;digo de la aplicaci&amp;oacute;n Rails y, como puede verse, este tiempo puede ser incluso mayor que el tiempo de ejecuci&amp;oacute;n de los tests.  Spork viene a resolver este problema.&lt;/p&gt;

&lt;h3&gt;Instalaci&amp;oacute;n&lt;/h3&gt;

&lt;p&gt;Spork se instala como cualquier otra gema, aunque como s&amp;oacute;lo se utiliza en el entorno de tests lo a&amp;ntilde;adiremos al grupo &lt;code&gt;test&lt;/code&gt; del &lt;code&gt;Gemfile&lt;/code&gt;.  Como lo estamos instalando para una aplicaci&amp;oacute;n Rails 3 tenemos que instalar la versi&amp;oacute;n de pre-lanzamiento que es la &lt;code&gt;0.9.0.rc&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;gem &amp;quot;rspec-rails&amp;quot;, :group =&amp;gt; [:test, :development]
group :test do
  gem &amp;quot;factory_girl_rails&amp;quot;43675-19804-85759-03545-08577
  gem &amp;quot;capybara&amp;quot;
  gem &amp;quot;guard-rspec&amp;quot;
  gem &amp;quot;spork&amp;quot;, &amp;quot;&amp;gt; 0.9.0.rc&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Como siempre, tras cambiar el &lt;code&gt;Gemfile&lt;/code&gt; tenemos que ejecutar &lt;code&gt;bundle&lt;/code&gt; para que se instalen todas las gemas y sus dependencias.&lt;/p&gt;


&lt;p&gt;Lo siguiente que tenemos que hacer es lanzar la orden &lt;code&gt;bootstrap&lt;/code&gt; de Spork para preparar el fichero &lt;code&gt;spec_helper&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ spork --bootstrap
Using RSpec
Bootstrapping /Users/eifion/auth/spec/spec_helper.rb.
Done. Edit /Users/eifion/auth/spec/spec_helper.rb now with your favorite text editor and follow the instructions.&lt;/pre&gt;

&lt;p&gt;Como puede verse, Spork ha detectado que estamos usando RSpec y ha modificado el fichero &lt;code&gt;spec_helper&lt;/code&gt;.  Ech&amp;eacute;mosle un vistazo a los cambios que ha hecho.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/spec_helper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require &amp;#x27;spork&amp;#x27;

Spork.prefork do
  # Loading more in this block will cause your tests to run faster. However,
  # if you change any configuration or code from libraries loaded here, you&amp;#x27;ll
  # need to restart spork for it take effect.

end

Spork.each_run do
  # This code will be run each time you run your specs.

end&lt;/pre&gt;

&lt;p&gt;Spork ha a&amp;ntilde;adido dos m&amp;eacute;todos en el fichero &lt;code&gt;spec_helper&lt;/code&gt;, cada uno de los cuales recibe un bloque.  El primero es &lt;code&gt;prefork&lt;/code&gt;, que se ejecuta cuando arranca el servidor de Spork.  El otro, llamado &lt;code&gt;each_run&lt;/code&gt; se ejecuta cada vez que ejecutamos la suite de tests.  La  idea es quitar todo el c&amp;oacute;digo que se pueda de  &lt;code&gt;spec_helper&lt;/code&gt; para pasarlo a &lt;code&gt;prefork&lt;/code&gt; de forma que s&amp;oacute;lo se ejecute una vez.  Moveremos todo el c&amp;oacute;digo de este archivo y veremos si los tests siguen pasando.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/spec_helper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require &amp;#x27;rubygems&amp;#x27;
require &amp;#x27;spork&amp;#x27;

Spork.prefork do
  # This file is copied to spec/ when you run &amp;#x27;rails generate &amp;crarr;
  rspec:install&amp;#x27;
  ENV[&amp;quot;RAILS_ENV&amp;quot;] ||= &amp;#x27;test&amp;#x27;
  require File.expand_path(&amp;quot;../../config/environment&amp;quot;, __FILE__)
  require &amp;#x27;rspec/rails&amp;#x27;
  require &amp;#x27;capybara/rspec&amp;#x27;

  # Requires supporting ruby files with custom matchers and &amp;crarr;
    macros, etc,
  # in spec/support/ and its subdirectories.
  Dir[Rails.root.join(&amp;quot;spec/support/**/*.rb&amp;quot;)].each {|f| &amp;crarr;
    require f}

  RSpec.configure do |config|
    config.mock_with :rspec
    config.use_transactional_fixtures = true
    config.include(MailerMacros)
    config.before(:each) { reset_email }
  end
end

Spork.each_run do
  # This code will be run each time you run your specs.
end&lt;/pre&gt;

&lt;p&gt;Podemos usar la orden &lt;code&gt;spork&lt;/code&gt; para arrancar su servidor.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ spork
Using RSpec
Preloading Rails environment
Loading Spork.prefork block...
Spork is ready and listening on 8989!&lt;/pre&gt;

&lt;p&gt;Cuando el servidor arranca ejecuta el c&amp;oacute;digo del m&amp;eacute;todo &lt;code&gt;prefork&lt;/code&gt; de forma que este c&amp;oacute;digo s&amp;oacute;lo se ejecuta una vez.  Ahora podemos lanzar otra ventana de terminal y ejecutar nuestra suite de tests.  Tenemos que ejecutar los tests mediante el servidor Spork, lo que se hace utilizando la opci&amp;oacute;n &lt;code&gt;--drb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Cuando Spork ejecuta los tests, la suite tarda menos en terminar, lo que podemos comprobar ejecut&amp;aacute;ndolo con la orden &lt;code&gt;time&lt;/code&gt; otra vez.  Esta mejora de velocidad se ir&amp;aacute; haciendo m&amp;aacute;s notable seg&amp;uacute;n vaya creciendo nuestra aplicaci&amp;oacute;n.&lt;/p&gt;


&lt;pre class="terminal"&gt;$ time rspec . --drb
.........

Finished in 2.21 seconds
9 examples, 0 failures

real	0m4.125s
user	0m0.342s
sys	0m0.097s&lt;/pre&gt;

&lt;p&gt;Spork es muy &amp;uacute;til porque carga todo el entorno de la aplicaci&amp;oacute;n una &amp;uacute;nica vez y luego va ejecutando los tests tantas veces como queramos sin tener que volver a recargar la aplicaci&amp;oacute;n cada vez.&lt;/p&gt;

&lt;h3&gt;Uso de Guard con Spork&lt;/h3&gt;

&lt;p&gt;Guard es una gema que lanza la suite de tests de una aplicaci&amp;oacute;n cada vez que se hacen cambios en el c&amp;oacute;digo.  La vimos en el episodio 264  [&lt;a href="http://railscasts.com/episodes/264-guard"&gt;verlo&lt;/a&gt;, &lt;a href="http://es.asciicasts.com/episodes/264-guard"&gt;leerlo&lt;/a&gt;].  Guard se puede utilizar con Spork mediante una gema llamada  &lt;code&gt;&lt;a href="https://github.com/guard/guard-spork"&gt;guard-spork&lt;/a&gt;&lt;/code&gt; que se instala igual que Spork a&amp;ntilde;adi&amp;eacute;ndola al grupo &amp;lt;ode&amp;gt;test&amp;lt;/ode&amp;gt; del &lt;code&gt;Gemfile&lt;/code&gt; y ejecutando &lt;code&gt;bundle&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;gem &amp;quot;rspec-rails&amp;quot;, :group =&amp;gt; [:test, :development]
group :test do
  gem &amp;quot;factory_girl_rails&amp;quot;
  gem &amp;quot;capybara&amp;quot;
  gem &amp;quot;guard-rspec&amp;quot;
  gem &amp;quot;spork&amp;quot;, &amp;quot;&amp;gt; 0.9.0.rc&amp;quot;
  gem &amp;quot;guard-spork&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Tras la instalaci&amp;oacute;n de la gema tenemos que ejecutar &lt;code&gt;guard init spork&lt;/code&gt; para a&amp;ntilde;adir Spork al &lt;code&gt;Guardfile&lt;/code&gt;.  Si luego inspeccionamos el &lt;code&gt;Guardfile&lt;/code&gt; veremos la secci&amp;oacute;n correspondiente a Spork bajo las configuraciones de RSpec.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Guardfile&lt;/p&gt;
&lt;pre class="ruby"&gt;guard &amp;#x27;spork&amp;#x27;, :cucumber_env =&amp;gt; { &amp;#x27;RAILS_ENV&amp;#x27; =&amp;gt; &amp;#x27;test&amp;#x27; }, :rspec_env =&amp;gt; { &amp;#x27;RAILS_ENV&amp;#x27; =&amp;gt; &amp;#x27;test&amp;#x27; } do
  watch(&amp;#x27;config/application.rb&amp;#x27;)
  watch(&amp;#x27;config/environment.rb&amp;#x27;)
  watch(%r{^config/environments/.+\.rb$})
  watch(%r{^config/initializers/.+\.rb$})
  watch(&amp;#x27;spec/spec_helper.rb&amp;#x27;)
end&lt;/pre&gt;

&lt;p&gt;Tenemos que  poner esta sobre la de RSpec porque se tiene que ejecutar antes que el resto de guardas relacionadas con los tests.  Tambi&amp;eacute;n tenemos que modificar la guarda de RSpec para a&amp;ntilde;adir la opci&amp;oacute;n &lt;code&gt;:cli&lt;/code&gt; con el valor &lt;code&gt;--drb&lt;/code&gt;.  Con esto haremos que los tests se ejecuten contra el servidor de Spork.  Lo mismo tendremos que hacer con el resto de guardas que tengamos para, por ejemplo, Cucumber.&lt;/p&gt;


&lt;pre class="terminal"&gt;guard &amp;#x27;rspec&amp;#x27;, :version =&amp;gt; 2, :cli =&amp;gt; &amp;#x27;--drb&amp;#x27; do
  # (se omite el contenido)
end&lt;/pre&gt;

&lt;p&gt;Con esto ya no tenemos que lanzar el servidor de Spork por separado. Cuando arranquemos Guard, &amp;eacute;ste lanzar&amp;aacute; autom&amp;aacute;ticamente Spork en segundo plano y ejecutar&amp;aacute; la suite de tests cuando cambiemos cualquiera de los ficheros Ruby de nuestra aplicaci&amp;oacute;n.&lt;/p&gt;


&lt;pre class="terminal"&gt;$ guard
Please install rb-fsevent gem for Mac OSX FSEvents support
Using polling (Please help us to support your system better than that.)
Please install growl_notify or growl gem for Mac OS X notification support and add it to your Gemfile
Guard is now watching at &amp;#x27;/Users/eifion/auth&amp;#x27;
Starting Spork for RSpec 
Using RSpec
Preloading Rails environment
Loading Spork.prefork block...
Spork is ready and listening on 8989!
Spork server for RSpec successfully started
Guard::RSpec is running, with RSpec 2!
Running all specs
Running tests with args [&amp;quot;--color&amp;quot;, &amp;quot;--format&amp;quot;, &amp;quot;progress&amp;quot;, &amp;quot;--format&amp;quot;, &amp;quot;Guard::RSpec::Formatter::NotificationRSpec&amp;quot;, &amp;quot;--out&amp;quot;, &amp;quot;/dev/null&amp;quot;, &amp;quot;--require&amp;quot;, &amp;quot;/Users/eifion/.rvm/gems/ruby-1.9.2-p180@rails31/gems/guard-rspec-0.4.5/lib/guard/rspec/formatters/notification_rspec.rb&amp;quot;, &amp;quot;spec&amp;quot;]...
.........

Finished in 4.29 seconds
9 examples, 0 failures
Done.&lt;/pre&gt;

&lt;p&gt;Esto es mucho m&amp;aacute;s f&amp;aacute;cil que tener que gestionar Spork por separado.  Cada vez que se cambie uno de los ficheros de nuestra aplicaci&amp;oacute;n se ejecutar&amp;aacute;n los tests relevantes aproximadamente un segundo despu&amp;eacute;s.&lt;/p&gt;

&lt;h3&gt;Configuraci&amp;oacute;n de Spork&lt;/h3&gt;


&lt;p&gt;Veamos ahora c&amp;oacute;mo configurar Spork.  A veces cuando cambiamos un fichero en nuestra aplicaci&amp;oacute;n Spork no refleja el cambio, lo que implica que tendremos que reinicarlo.  Esto ocurre porque el fichero se carga en el bloque &lt;code&gt;prefork&lt;/code&gt; pero no se recarga en &lt;code&gt;each_run&lt;/code&gt; y es algo que  pasa con frecuencia si usamos Factory Girl.  Las factor&amp;iacute;as se cargan en &lt;code&gt;prefork&lt;/code&gt; por lo que los cambios que hagamos no surtir&amp;aacute;n efecto cuando se vuelva a lanzar la suite de tets.  Como queremos que estos cambios ocurran autom&amp;aacute;ticamente tenemos que recargar las factor&amp;iacute;as en &lt;code&gt;each_run&lt;/code&gt;.  Las versiones m&amp;aacute;s recientes de Factory Girl tienen un m&amp;eacute;todo &lt;code&gt;reload &lt;/code&gt;  que nos pone las cosas muy f&amp;aacute;ciles:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/spec_helper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;Spork.each_run do
  FactoryGirl.reload
end&lt;/pre&gt;

&lt;p&gt;Ahora los cambios que hagamos en las factor&amp;iacute;as surtir&amp;aacute;n efecto cada vez que se ejecuten los tests.&lt;/p&gt;

&lt;p&gt;Puede ocurrir un problema parecido con los ficheros que se encuentren en &lt;code&gt;/spec/support&lt;/code&gt;.  De nuevo, estos archivos se cargan dentro del bloque &lt;code&gt;prefork&lt;/code&gt;, por lo que no se coger&amp;aacute;n cuando se vuelva a ejecutar la suite de tests.  Podr&amp;iacute;amos mover el c&amp;oacute;digo de carga a &lt;code&gt;each_run&lt;/code&gt; pero cuanto  m&amp;aacute;s c&amp;oacute;digo pongamos en este m&amp;eacute;todo m&amp;aacute;s tardar&amp;aacute;n los tests en empezar a pasar.  Ser&amp;iacute;a mejor poder mantener el c&amp;oacute;digo en el bloque &lt;code&gt;preload&lt;/code&gt; y recargar Spork autom&amp;aacute;ticamente cada vez que se modifiquen los archivos en &lt;code&gt;/spec/support&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para esto nos puede servir &lt;code&gt;guard-spork&lt;/code&gt;.  El &lt;code&gt;Guardfile&lt;/code&gt; contiene un listado de patrones de archivo en el bloque &lt;code&gt;spork&lt;/code&gt; que define los ficheros a vigilar.  Aqu&amp;iacute; podemos a&amp;ntilde;adir el directorio &lt;code&gt;spec/support&lt;/code&gt; para que se reinicie el servidor Spork cada vez que se produzca un cambio.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/Guardfile&lt;/p&gt;
&lt;pre class="ruby"&gt;guard &amp;#x27;spork&amp;#x27;, :cucumber_env =&amp;gt; { &amp;#x27;RAILS_ENV&amp;#x27; =&amp;gt; &amp;crarr;
  &amp;#x27;test&amp;#x27; }, :rspec_env =&amp;gt; { &amp;#x27;RAILS_ENV&amp;#x27; =&amp;gt; &amp;#x27;test&amp;#x27; } do
  watch(&amp;#x27;config/application.rb&amp;#x27;)
  watch(&amp;#x27;config/environment.rb&amp;#x27;)
  watch(%r{^config/environments/.+\.rb$})
  watch(%r{^config/initializers/.+\.rb$})
  watch(&amp;#x27;spec/spec_helper.rb&amp;#x27;)
  watch(%r{^spec/support/.+\.rb$})
end&lt;/pre&gt;

&lt;p&gt;Con esto los cambios en &lt;code&gt;spec/support&lt;/code&gt; ser&amp;aacute;n detectados por Guard, que reiniciar&amp;aacute; Spork.&lt;/p&gt;

&lt;p&gt;Ya que estamos mirando el fichero &lt;code&gt;Guardfile&lt;/code&gt; veamos un truco para utilizar con  suites de tests lentas.  Si los tests tardan m&amp;aacute;s de un minuto en pasar seguramente no querremos ejecutarlos con tanta frecuencia, por lo que hay dos argumentos a &lt;code&gt;rspec guard&lt;/code&gt; que nos pueden ser de ayuda: &lt;code&gt;all_on_start&lt;/code&gt; y &lt;code&gt;all_after_pass&lt;/code&gt;.  Podemos hacer que los dos sean &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Guardfile&lt;/p&gt;
&lt;pre class="ruby"&gt;guard &amp;#x27;rspec&amp;#x27;, :version =&amp;gt; 2, :cli =&amp;gt; &amp;#x27;--drb&amp;#x27;, &amp;crarr;
  :all_on_start =&amp;gt; false, :all_after_pass =&amp;gt; false do
  
# watch commands omitted.
end&lt;/pre&gt;

&lt;p&gt;Con estas opciones Guard no ejecutar&amp;aacute; todos los tests cuando pase un test que antes fallaba, lo que nos da m&amp;aacute;s control sobre cu&amp;aacute;ndo se ejecutan todos los tests.  Para lanzar todos los tests podemos pulsar la tecla de retorno en el terminal de Guard (si utilizamos la &amp;uacute;ltima versi&amp;oacute;n).&lt;/p&gt;

&lt;p&gt;Otro truco que no tiene que ver con Spork pero que resulta &amp;uacute;til cuando tenemos una suite de tests grande es a&amp;ntilde;adir tres l&amp;iacute;neas en el bloque de configuraci&amp;oacute;n de RSpec (las tres l&amp;iacute;neas del final).&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/spec_helper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;RSpec.configure do |config|
  config.mock_with :rspec
  config.use_transactional_fixtures = true
  config.include(MailerMacros)
  config.before(:each) { reset_email }
    
  config.treat_symbols_as_metadata_keys_with_true_values = true
  config.filter_run :focus =&amp;gt; true
  config.run_all_when_everything_filtered = true
end&lt;/pre&gt;

&lt;p&gt;Si ahora a&amp;ntilde;adimos la etiqueta &lt;code&gt;:focus&lt;/code&gt; en una especificaci&amp;oacute;n, s&amp;oacute;lo se ejecutar&amp;aacute; dicho tests en lugar de todos.  Por ejemplo si a&amp;ntilde;adimos &lt;code&gt;:focus&lt;/code&gt; en un tests del modelo &lt;code&gt;User&lt;/code&gt;:&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/spec/models/user_spec.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require &amp;#x27;spec_helper&amp;#x27;

describe User do
  describe &amp;quot;#send_password_reset&amp;quot; do
    let(:user) { Factory(:user) }

    it &amp;quot;generates a unique password_reset_token each time&amp;quot;, &amp;crarr;
      :focus do
      user.send_password_reset
      last_token = user.password_reset_token
      user.send_password_reset
      user.password_reset_token.should_not eq(last_token)
    end

	# Other specs omitted.
  end
end&lt;/pre&gt;

&lt;p&gt;Cuando guardemos este archivo, Guard detectar&amp;aacute; los cambios pero como se usa la etiqueta &lt;code&gt;:focus&lt;/code&gt; s&amp;oacute;lo se ejecutar&amp;aacute; la especificaci&amp;oacute;n anterior.&lt;/p&gt;

&lt;pre class="terminal"&gt;Running: spec/models/user_spec.rb
Running tests with args ...
Run filtered including {:focus=&amp;gt;true}
.

Finished in 1.93 seconds
1 example, 0 failures
Done.&lt;/pre&gt;

&lt;p&gt;Hay otros casos en los que hay un fragmento de c&amp;oacute;digo que se ejecuta en el bloque &lt;code&gt;prefork&lt;/code&gt; y no hay una manera sencilla de moverlo a &lt;code&gt;each_run&lt;/code&gt;.  Spork proporciona el m&amp;eacute;todo &lt;code&gt;trap_method&lt;/code&gt; para controlar estos escnarios.  Este m&amp;eacute;todo hace que el m&amp;eacute;todo &lt;em&gt;atrapado&lt;/em&gt; no se ejecute inmediatamente y lo lanza despu&amp;eacute;s de lanzar el proceso.  Esto es &amp;uacute;til en algunos casos como con Mongoid o Devise, los cuales cargan cosas en el bloque &lt;code&gt;prefork&lt;/code&gt; que realmente no queremos que se carguen ah&amp;iacute;.  Esto se explica en detalle en  &lt;a href="https://github.com/timcharper/spork/wiki/Spork.trap_method-Jujutsu"&gt;el wiki de Spork&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Con esto concluimos este episodio dedicado a Spork, que es una herramienta muy c&amp;oacute;moda para acelerar el proceso TDD y que escala muy bien con proyectos Rails grandes si se combina con los trucos que hemos visto.&lt;/p&gt;
</description>
      <pubDate>Sun, 16 Oct 2011 22:21:29 +0000</pubDate>
      <guid>http://es.asciicasts.com/episodes/285-spork</guid>
      <link>http://es.asciicasts.com/episodes/285-spork</link>
    </item>
    <item>
      <title>Active Admin</title>
      <description>&lt;p&gt;Vamos a dedicar este episodio a  &lt;a href="http://activeadmin.info"&gt;Active Admin&lt;/a&gt;, que es una gema con la que podemos a&amp;ntilde;adir f&amp;aacute;cilmente una interfaz de administraci&amp;oacute;n a nuestras aplicaciones Rails.  La interfaz que se genera tiene un aspecto cuidado y muy personalizable.  Se puede ver en acci&amp;oacute;n entrando en la  &lt;a href="http://demo.activeadmin.info/admin"&gt;demo en vivo&lt;/a&gt;.&lt;/p&gt; 

&lt;p&gt;En este episodio vamos a integrar Active Admin sobre una aplicaci&amp;oacute;n Rails ya existente.  La aplicaci&amp;oacute;n con la que trabajaremos  es una aplicaci&amp;oacute;n muy sencilla de comercio electr&amp;oacute;nico que tiene varios productos, cada uno de ellos con su precio y categor&amp;iacute;a.  Utilizaremos ActiveAdmin para crear una interfaz de administraci&amp;oacute;n que permita gestionar nuestros productos.&lt;/p&gt;


&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/735/original/E284I01.png" width="799" height="460" alt="La aplicaci&#243;n."/&gt;
&lt;/div&gt;

&lt;h3&gt;Instalaci&amp;oacute;n de Active Admin&lt;/h3&gt;

&lt;p&gt;Active Admin es una gema que se instala, como es habitual, a&amp;ntilde;adiendo una referencia en el &lt;code&gt;Gemfile&lt;/code&gt; y ejecutando a continuaci&amp;oacute;n &lt;code&gt;bundle&lt;/code&gt;.  La aplicaci&amp;oacute;n es una aplicaci&amp;oacute;n Rails 3.1 por lo que debemos asegurarnos de incluir la gema &lt;code&gt;sass-rails&lt;/code&gt; porque Active Admin depende de ella.  En Rails 3.0 no nos har&amp;iacute;a falta incluirla.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;gem &amp;#x27;activeadmin&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Una vez que Bundler ha terminado, para a&amp;ntilde;adir Active Admin  tenemos que ejecutar un generador en nuestra aplicaci&amp;oacute;n.  Este generador adem&amp;aacute;s nos dar&amp;aacute; instrucciones adicionales que podremos configurar despu&amp;eacute;s.  Tenemos que a&amp;ntilde;adir la opci&amp;oacute;n &lt;code&gt;host&lt;/code&gt; a la configuraci&amp;oacute;n del correo en el entorno de desarrollo y asegurarnos de que tenemos una URL ra&amp;iacute;z y mostramos los mensajes &lt;code&gt;notice&lt;/code&gt; y &lt;code&gt;alert&lt;/code&gt; en el &lt;em&gt;layout&lt;/em&gt; de la aplicaci&amp;oacute;n.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g active_admin:install
      invoke  devise
    generate    devise:install
      create    config/initializers/devise.rb
      create    config/locales/devise.en.yml
  
==================================================================

Some setup you must do manually if you haven&amp;#x27;t yet:

  1. Setup default url options for your specific environment. Here is an example of development environment:

       config.action_mailer.default_url_options = { :host =&amp;gt; &amp;#x27;localhost:3000&amp;#x27; }

     This is a required Rails configuration. In production it must be the actual host of your application

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root :to =&amp;gt; &amp;quot;home#index&amp;quot;

  3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example:

       &amp;lt;p class=&amp;quot;notice&amp;quot;&amp;gt;&amp;lt;%= notice %&amp;gt;&amp;lt;/p&amp;gt;
       &amp;lt;p class=&amp;quot;alert&amp;quot;&amp;gt;&amp;lt;%= alert %&amp;gt;&amp;lt;/p&amp;gt;&lt;/pre&gt;

&lt;p&gt;Nosotros ya tenemos todo esto en nuestra aplicaci&amp;oacute;n por lo que podemos continuar.&lt;/p&gt;

&lt;p&gt;La orden tambi&amp;eacute;n crea alguna migraciones que tenemos que ejecutar.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rake db:migrate&lt;/pre&gt;

&lt;h3&gt;Uso de Active Admin&lt;/h3&gt;


&lt;p&gt;En  la &lt;a href="http://activeadmin.info/documentation.html"&gt;documentaci&amp;oacute;n de Active Admin&lt;/a&gt; se indica que durante la migraci&amp;oacute;n inicial se crear&amp;aacute; un usuario con el nombre  &lt;code&gt;admin@example.com&lt;/code&gt; y la clave &lt;code&gt;password&lt;/code&gt;. Podemos iniciar la sesi&amp;oacute;n con estos credenciales (por supuesto estos valores se pueden modificar editando el fichero de migraci&amp;oacute;n &lt;code&gt;devise_create_admin_users.rb&lt;/code&gt; antes de lanzar las migraciones)  Visitando  &lt;a href="http://localhost:3000/admin"&gt;http://localhost:3000/admin&lt;/a&gt; con el servidor Rails en marcha veremos un formulario de inicio de sesi&amp;oacute;n donde podemos introducir dichas credenciales.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/736/original/E284I02.png" width="799" height="458" alt="Inicio de sesi&#243;n de Active Admin"
&lt;/div&gt;

&lt;p&gt;Tras el inicio de sesi&amp;oacute;n seremos llevados al cuadro de mandos de Active Admin, donde no encontraremos mucho que ver.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/737/original/E284I03.png" width="799" height="458" alt="El cuadro de mandos de Active Admin."/&gt;
&lt;/div&gt;

&lt;p&gt;Como queremos gestionar nuestros productos a&amp;ntilde;adiremos el recurso &lt;code&gt;Product&lt;/code&gt; a Active Admin ejecutando la orden:&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g active_admin:resource product
      create  app/admin/products.rb&lt;/pre&gt;

&lt;p&gt;Este generador crea un fichero llamado &lt;code&gt;products.rb&lt;/code&gt; bajo el directorio &lt;code&gt;app/admin&lt;/code&gt; de la aplicaci&amp;oacute;n.  Si refrescamos el cuadro de mandos de la aplicaci&amp;oacute;n ahora veremos un enlace con el texto  &amp;ldquo;Products&amp;rdquo; y si hacemos clic iremos a una p&amp;aacute;gina que tiene todo lo necesario para gestionar los productos.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/738/original/E284I04.png" width="802" height="474" alt="El &#237;ndice de la administraci&#243;n de productos."/&gt;
&lt;/div&gt;

&lt;p&gt;En la p&amp;aacute;gina hay opciones para ordenar o filtrar el listado de productos por cualquier atributo.  Active Admin detectar&amp;aacute; incluso las relaciones &lt;code&gt;belongs_to&lt;/code&gt; con &lt;code&gt;Category&lt;/code&gt; e implementar&amp;aacute; un men&amp;uacute; desplegable para poder filtrar los productos por dicha categor&amp;iacute;a.  Esto tambi&amp;eacute;n ocurre cuando creamos un nuevo producto y se muestra un desplegable para escoger la categor&amp;iacute;a. El resto de atributos tendr&amp;aacute;n campos de entrada acordes con su tipo de datos.&lt;/p&gt;
 
&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/739/original/E284I05.png" width="802" height="474" alt="La p&#225;gina de nuevo producto."/&gt;
&lt;/div&gt;

&lt;p&gt;Esta funcionalidad es f&amp;aacute;cil de modificar.  Empecemos personalizando el &amp;iacute;ndice de productos quitando columnas.  Para ello modificaremos el fichero  &lt;code&gt;/app/admin/products.rb&lt;/code&gt; anteriormente generado.  Podemos cambiar el listado principal redefiniendo el m&amp;eacute;todo &lt;code&gt;index&lt;/code&gt;.  Este m&amp;eacute;todo recibe un bloque dentro del cual podemos especificar las columnas que deseamos ver en la p&amp;aacute;gina invocando a &lt;code&gt;column&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  index do
    column :name
    column :category
    column :released_at
    column :price
  end
end&lt;/pre&gt;

&lt;p&gt;Si recargamos la p&amp;aacute;gina de productos veremos que ahora muestra s&amp;oacute;lo las columnas que queremos.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/740/original/E284I06.png" width="802" height="474" alt="En la p&#225;gina de productos ahora aparece las columnas escogidas por nosotros."/&gt;
&lt;/div&gt;


&lt;p&gt;Obs&amp;eacute;rvese que la asociaci&amp;oacute;n con &lt;code&gt;Category&lt;/code&gt; ha sido detectada autom&amp;aacute;ticamente  y junto a cada producto se muestra la categor&amp;iacute;a correcta.&lt;/p&gt;

&lt;p&gt;Podemos ir m&amp;aacute;s lejos y cambiar el t&amp;iacute;tulo de la columna pasando el t&amp;iacute;tulo como primer argumento.  Cambiaremos de esta forma el campo &lt;code&gt;released_at&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  index do
    column :name
    column :category
    column &amp;quot;Release Date&amp;quot;, :released_at
    column :price
  end
end&lt;/pre&gt;

&lt;p&gt;Si queremos cambiar los valores de una columna podemos hacerlo pasando un bloque a &lt;code&gt;column&lt;/code&gt;.  El campo de precio no muestra un s&amp;iacute;mbolo monetario, pero podemos cambiarlo para que lo haga.  El m&amp;eacute;todo &lt;code&gt;column&lt;/code&gt; puede recibir un bloque, en cuyo caso se le pasar&amp;iacute;a la instancia (en este caso un &lt;code&gt;Product&lt;/code&gt;) y se mostrar&amp;iacute;a en la columna lo que devuelva el bloque.  Aqu&amp;iacute; tenemos acceso a los m&amp;eacute;todos &lt;em&gt;helper&lt;/em&gt; por lo que podemos utilizar &lt;code&gt;number_to_currency&lt;/code&gt; para mostrar correctamente el precio.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  index do
    column :name
    column :category
    column &amp;quot;Release Date&amp;quot;, :released_at
    column :price do |product|
      number_to_currency product.price, :unit =&amp;gt; &amp;quot;&amp;amp;pound;&amp;quot;
    end
  end
end&lt;/pre&gt;

&lt;p&gt;Si recargamos la p&amp;aacute;gina veremos el t&amp;iacute;tulo modificado y el precio correcto para cada producto.&lt;/p&gt;


&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/741/original/E284I07.png" width="802" height="474" alt="En la columna de precio ya aparecen los precios correctamente."/&gt;
&lt;/div&gt;

&lt;p&gt;Pero si personalizamos el valor devuelto para el campo &lt;code&gt;price&lt;/code&gt; entonces ya no podemos ordenar por dicho campo, y tampoco tenemos enlaces de edici&amp;oacute;n y borrado para cada elemento.  Esto lo tenemos que corregir, siempre que usemos un bloque para personalizar un valor tambi&amp;eacute;n debemos usar la opci&amp;oacute;n &lt;code&gt;:sortable&lt;/code&gt; para que Active Admin sepa c&amp;oacute;mo ordenar la columna.  A&amp;ntilde;adiremos tambi&amp;eacute;n &lt;code&gt;default_actions&lt;/code&gt; para que vuelvan a aparecer los enlaces de edici&amp;oacute;n y borrado.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  index do
    column :name
    column :category
    column &amp;quot;Release Date&amp;quot;, :released_at
    column :price, :sortable =&amp;gt; :price do |product|
      number_to_currency product.price, :unit =&amp;gt; &amp;quot;&amp;amp;pound;&amp;quot;
    end
    default_actions
  end
end&lt;/pre&gt;

&lt;p&gt;En el campo de precio ahora se muestra el s&amp;iacute;mbolo monetario pero ser&amp;iacute;a mejor poder alinear los valores a la derecha.  Esto lo podemos hacer con CSS, pero para eso tenemos que poder identificar la columna.  Active Admin proporciona una manera de generar HTML muy similar a  &lt;a href="http://markaby.github.com/"&gt;Markaby&lt;/a&gt;, tan s&amp;oacute;lo tenemos que llamar un m&amp;eacute;todo con el nombre de la etiqueta que deseamos generar.  Podemos pasar la opci&amp;oacute;n &lt;code&gt;:class&lt;/code&gt; para que la etiqueta tenga algo que podamos controlar desde CSS.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  index do
    column :name
    column :category
    column &amp;quot;Release Date&amp;quot;, :released_at
    column :price, :sortable =&amp;gt; :price do |product|
      div :class =&amp;gt; &amp;quot;price&amp;quot; do
        number_to_currency product.price, :unit =&amp;gt; &amp;quot;&amp;amp;pound;&amp;quot;
      end
    end
    default_actions
  end
end&lt;/pre&gt;

&lt;p&gt;Ya podemos dar estilos a esta columna modificando el fichero &lt;code&gt;active_admin.css.scss&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/active_admin.css.scss&lt;/p&gt;
&lt;pre class="css"&gt;// Active Admin CSS Styles
@import &amp;quot;active_admin/mixins&amp;quot;;
@import &amp;quot;active_admin/base&amp;quot;;

// To customize the Active Admin interfaces, add your
// styles here:
.price {
  text-align :right;
}&lt;/pre&gt;

&lt;p&gt;Y la columna con precios se alinear&amp;aacute; correctamente.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/742/original/E284I08.png" width="802" height="472" alt="La columna de precios justificada a la derecha."/&gt;
&lt;/div&gt;

&lt;h3&gt;&amp;Aacute;mbitos&lt;/h3&gt;

&lt;p&gt;Otra interesante funcionalidad de Active Admin son los &amp;aacute;mbitos, que se comportan como filtros predefinidos.  Para crear estos &amp;aacute;mbitos hay que seguir dos pasos. Primero a&amp;ntilde;adimos una llamada a &lt;code&gt;scope&lt;/code&gt; en el fichero de configuraci&amp;oacute;n de nuestros productos, pas&amp;aacute;ndoles el nombre de un &amp;aacute;mbito.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  scope :unreleased
  index do
    column :name
    column :category
    column &amp;quot;Release Date&amp;quot;, :released_at
    column :price, :sortable =&amp;gt; :price do |product|
      div :class =&amp;gt; &amp;quot;price&amp;quot; do
        number_to_currency product.price, :unit =&amp;gt; &amp;quot;&amp;amp;pound;&amp;quot;
      end
    end
    default_actions
  end
end&lt;/pre&gt;

&lt;p&gt;Y luego necesitamos escribir dicho &amp;aacute;mbito en el modelo correspondiente:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/product.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Product &amp;lt; ActiveRecord::Base
  belongs_to :category
  scope :unreleased, where(:released_at =&amp;gt; nil)
end&lt;/pre&gt;

&lt;p&gt;Si ahora volvemos a cargar la p&amp;aacute;gina de administraci&amp;oacute;n de productos veremos listado el &amp;aacute;mbito.  Si hacemos clic en &amp;eacute;l veremos un listado de productos filtrado por dicho &amp;aacute;mbito.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/743/original/E284I09.png" width="802" height="472" alt="Listado de productos filtrado por el &#225;mbito correspondiente."/&gt;
&lt;/div&gt;

&lt;h3&gt;Personalizaci&amp;oacute;n del cuadro de mandos&lt;/h3&gt;

&lt;p&gt;A continuaci&amp;oacute;n veremos c&amp;oacute;mo personalizar el cuadro de mandos.  Por defecto aparece vac&amp;iacute;o, as&amp;iacute; que mostraremos un listado de los productos m&amp;aacute;s recientes, lo que haremos modificando el fichero &lt;code&gt;/app/admin/dashboards.rb&lt;/code&gt;.  En los comentarios del archivo se documentan las posibilidades de las que disponemos.&lt;/p&gt;


&lt;p&gt;Para a&amp;ntilde;adir una secci&amp;oacute;n al cuadro de mandos se utiliza el m&amp;eacute;todo &lt;code&gt;section&lt;/code&gt;.  Queremos enumerar los productos m&amp;aacute;s recientes en una tabla, lo que podemos hacer con &lt;code&gt;table_for&lt;/code&gt;.  En el bloque podemos definir qu&amp;eacute; columnas queremos mostrar con &lt;code&gt;column&lt;/code&gt; de la misma forma que hicimos cuando personalizamos el &amp;iacute;ndice de productos.  Tambi&amp;eacute;n a&amp;ntilde;adiremos un enlace a la p&amp;aacute;gina que muestra todos los productos.&lt;/p&gt;
&lt;p class="codeFilePath"&gt;/app/admin/dashboards.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin::Dashboards.build do
  section &amp;quot;Recent Products&amp;quot; do
    table_for Product.order(&amp;quot;released_at desc&amp;quot;).limit(5) do
      column :name
      column :released_at
    end
    strong { link_to &amp;quot;View All Products&amp;quot;, admin_products_path }
  end
end&lt;/pre&gt;

&lt;p&gt;Si ahora recargamos el panel de control veremos los cinco productos m&amp;aacute;s recientes, as&amp;iacute; como el enlace.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/744/original/E284I10.png" width="802" height="472" alt="El listado de productos m&#225;s recientes en el cuadro de mandos."/&gt;
&lt;/div&gt;

&lt;p&gt;La p&amp;aacute;gina ser&amp;iacute;a m&amp;aacute;s &amp;uacute;til si cada producto del listado enlazase a la p&amp;aacute;gina de administraci&amp;oacute;n de dicho producto.  Esto lo podemos hacer pas&amp;aacute;ndole un bloque al m&amp;eacute;todo &lt;code&gt;column&lt;/code&gt;, igual que hicimos con la columna &lt;code&gt;price&lt;/code&gt; anteriormente.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/dashboards.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin::Dashboards.build do
  section &amp;quot;Recent Products&amp;quot; do
    table_for Product.order(&amp;quot;released_at desc&amp;quot;).limit(5) do
      column :name do |product|
        link_to product.title, admin_product_path(product)
      end
      column :released_at
    end
    strong { link_to &amp;quot;View All Products&amp;quot;, admin_products_path }
  end
end&lt;/pre&gt;

&lt;p&gt;Hay una forma m&amp;aacute;s breve de definir una ruta en &lt;code&gt;link_to&lt;/code&gt;.  En lugar de utilizar &lt;code&gt;admin_product_path(product)&lt;/code&gt; podemos pasar un &lt;em&gt;array&lt;/em&gt; con un s&amp;iacute;mbolo como primer elemento y el producto como el segundo:&lt;/p&gt;
  
&lt;pre class="ruby"&gt;link_to product.title, [:admin, product]&lt;/pre&gt;

&lt;p&gt;Si recargamos el cuadro de mandos veremos el t&amp;iacute;tulo de cada producto como un enlace que nos llevar&amp;aacute; a la p&amp;aacute;gina correspondiente de administraci&amp;oacute;n de dicho producto.&lt;/p&gt;

&lt;h3&gt;Ajustes en las hojas de estilo&lt;/h3&gt;

&lt;p&gt;Hay un problema que debemos tener en cuenta cuando utilizamos Active Admin en Rails 3.1, que podemos ver volviendo al sitio principal.&lt;/p&gt;

 &lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/745/original/E284I11.png" width="801" height="435" alt="The home page now has incorrect styling."/&gt;
&lt;/div&gt;

&lt;p&gt;La p&amp;aacute;gina no tiene el aspecto que ten&amp;iacute;a antes porque ahora se incluye en todas las p&amp;aacute;ginas la hoja de estilos de Active Admin.  Rails 3.1 incluye todas las hojas de estilos por defecto, debido a la presencia de la l&amp;iacute;nea con &lt;code&gt;require_tree .&lt;/code&gt; en el fichero de manifiesto de &lt;code&gt;application.css&lt;/code&gt;.  Como esto no es lo que queremos (y adem&amp;aacute;s siempre es buena idea hacerlo para tener m&amp;aacute;s control sobre los estilos de nuestras aplicaci&amp;oacute;n) vamos a cambiar &lt;code&gt;require_tree .&lt;/code&gt; por &lt;code&gt;require products&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/application.css&lt;/p&gt;
&lt;pre class="css"&gt;/*
 * This is a manifest file that&amp;#x27;ll automatically include all the stylesheets available in this directory
 * and any sub-directories. You&amp;#x27;re free to add application-wide styles to this file and they&amp;#x27;ll appear at
 * the top of the compiled file, but it&amp;#x27;s generally better to create a new file per style scope.
 *= require_self
 *= require products 
*/

/* Se omite el resto del archivo */&lt;/pre&gt;

&lt;p&gt;Una soluci&amp;oacute;n todav&amp;iacute;a mejor es pasarnos a la orden &lt;code&gt;import&lt;/code&gt; de SASS.  Podemos hacer que el fichero CSS de nuestra aplicaci&amp;oacute;n sea SASS a&amp;ntilde;adiendo la extensi&amp;oacute;n &lt;code&gt;.scss&lt;/code&gt; a su nombre.  Luego podemos quitar el manifiesto de la parte superior y a&amp;ntilde;adir al final la orden &lt;code&gt;import&lt;/code&gt;:&lt;/p&gt;
&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/application.css.scss&lt;/p&gt;
&lt;pre class="css"&gt;/* (Se omiten los estilos)*/

@import &amp;quot;products&amp;quot;;&lt;/pre&gt;

&lt;p&gt;Si recargamos la p&amp;aacute;gina principal s&amp;oacute;lo se incluyen las p&amp;aacute;ginas de estilos correspondientes y la p&amp;aacute;gina tiene el aspecto correcto.&lt;/p&gt;

&lt;h3&gt;Configuraci&amp;oacute;n global&lt;/h3&gt;

&lt;p&gt;Hay otro archivo para configurar Active Admin en el directorio &lt;code&gt;/config/initializers&lt;/code&gt; donde hay bastantes opciones de configuraci&amp;oacute;n que aparecen comentadas.  Una que no lo est&amp;aacute; es el fichero con el t&amp;iacute;tulo del sitio, que cambiaremos.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/initializers/active_admin.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.setup do |config|

  # == Site Title
  #
  # Set the title that is displayed on the main layout
  # for each of the active admin pages.
  #
  config.site_title = &amp;quot;Eifion&amp;#x27;s Store&amp;quot;

  # (Se omiten otras opciones de configuraci&amp;oacute;n)
end&lt;/pre&gt;

&lt;p&gt;Para que estos cambios surtan efecto debemos reiniciar el servidor, tras hacerlo aparecer&amp;aacute; el t&amp;iacute;tulo correcto.&lt;/p&gt;


&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/746/original/E284I12.png" width="801" height="435" alt="Se muestra el nuevo t&#237;tulo."/&gt;
&lt;/div&gt;

&lt;p&gt;Con esto terminamos este episodio.  Hay muchas m&amp;aacute;s cosas que se pueden adaptar en Active Admin y que no hemos repasado hoy, merece la pena ver la documentaci&amp;oacute;n para ver qu&amp;eacute; m&amp;aacute;s cosas podemos hacer.  Podemos modificar el aspecto y la funcionalidad de todas las p&amp;aacute;ginas de Active Admin para adaptarlas a nuestras necesidades, por lo que es una soluci&amp;oacute;n muy poderosa para a&amp;ntilde;adir la funcionalidad de administraci&amp;oacute;n en nuestras aplicaciones Rails.&lt;/p&gt;
</description>
      <pubDate>Sun, 16 Oct 2011 22:18:41 +0000</pubDate>
      <guid>http://es.asciicasts.com/episodes/284-active-admin</guid>
      <link>http://es.asciicasts.com/episodes/284-active-admin</link>
    </item>
    <item>
      <title>Autenticaci&#243;n usando Sorcery</title>
      <description>&lt;p&gt;En el episodio 250 [&lt;a href="http://railscasts.com/episodes/250-authentication-from-scratch"&gt;verlo&lt;/a&gt;, &lt;a href="http://es.asciicasts.com/episodes/250-autenticacion-desde-cero"&gt;leerlo&lt;/a&gt;] implementamos un esquema de autenticaci&amp;oacute;n en una aplicaci&amp;oacute;n Rails partiendo de cero.  Si preferimos utilizar una soluci&amp;oacute;n ya construida hay varias gemas disponibles, en este episodio veremos una llamada  &lt;a href="https://github.com/NoamB/sorcery"&gt;Sorcery&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Sorcery es una soluci&amp;oacute;n muy sencilla.  Tan s&amp;oacute;lo ofrece unos veinte m&amp;eacute;todos que se bastan para proporcionar todas las funciones de autenticaci&amp;oacute;n necesarias.  A pesar de su simplicidad, es una soluci&amp;oacute;n completa y modular de forma que podemos  activar s&amp;oacute;lo las partes que deseemos, por ejemplo la recuperaci&amp;oacute;n de contrase&amp;ntilde;as, registro de actividad, etc.  Sorcery funciona a un nivel m&amp;aacute;s bajo que otras gemas de autenticaci&amp;oacute;n dejando de nuestra parte la tarea de escribir las capas de vista y controlador.  En este episodio lo utilizaremos para a&amp;ntilde;adir autenticaci&amp;oacute;n a una aplicaci&amp;oacute;n Rails ya existente.&lt;/p&gt;

&lt;h3&gt;Empezando&lt;/h3&gt;

&lt;p&gt;La aplicaci&amp;oacute;n con la que vamos a trabajar es muy sencilla, tiene una p&amp;aacute;gina de bienvenida con un enlace a una p&amp;aacute;gina secreta.  Dicha p&amp;aacute;gina puede ser vista por cualquiera pero queremos restringir el acceso s&amp;oacute;lo a los usuarios que hayan iniciado sesi&amp;oacute;n.  Usaremos Sorcery para implementar este tipo de autenticaci&amp;oacute;n.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/730/original/E283I01.png" width="804" height="366" alt="La aplicaci&#243;n."/&gt;
&lt;/div&gt;

&lt;p&gt;Sorcery se distribuye como gema y se instala de la forma habitual a&amp;ntilde;adiendo una referencia en el &lt;code&gt;Gemfile&lt;/code&gt; y ejecutando a continuaci&amp;oacute;n &lt;code&gt;bundle&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;gem &amp;#x27;sorcery&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Despu&amp;eacute;s de que Bundler haga su trabajo tenemos que ejecutar la siguiente orden para a&amp;ntilde;adir el fichero de inicializaci&amp;oacute;n de Sorcery (que m&amp;aacute;s adelante veremos).&lt;/p&gt;

&lt;pre class="ruby"&gt;$ rake sorcery:bootstrap&lt;/pre&gt;

&lt;p&gt;Lo siguiente es generar una migraci&amp;oacute;n con &lt;code&gt;sorcery_migration&lt;/code&gt;.  Aqu&amp;iacute; podemos escoger los m&amp;oacute;dulos de Sorcery que deseamos incluir.  Nosotros incluiremos la funcionalidad &lt;code&gt;core&lt;/code&gt; que implementa una autenticaci&amp;oacute;n simple basada en clave y el m&amp;oacute;dulo &lt;code&gt;remember_me&lt;/code&gt;.  Se puede ver un listado completo de los m&amp;oacute;dulos en  &lt;a href="https://github.com/NoamB/sorcery/blob/master/README.rdoc"&gt;el README de Sorcery&lt;/a&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g sorcery_migration core remember_me
      create  db/migrate/20110914221626_sorcery_core.rb
      create  db/migrate/20110914221627_sorcery_remember_me.rb&lt;/pre&gt;

&lt;p&gt;Esta orden crea varios ficheros de migraci&amp;oacute;n (dependiendo de los m&amp;oacute;dulos que hayamos escogido), si examinamos la migraci&amp;oacute;n  &lt;code&gt;sorcery_core&lt;/code&gt; veremos los atributos que se a&amp;ntilde;aden a la tabla &lt;code&gt;users&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/db/migrate/20110914221626_sorcery_core.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class SorceryCore &amp;lt; ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :username,         :null =&amp;gt; false  
      t.string :email,            :default =&amp;gt; nil 
      t.string :crypted_password, :default =&amp;gt; nil
      t.string :salt,             :default =&amp;gt; nil
      t.timestamps
    end
  end

  def self.down
    drop_table :users
  end
end&lt;/pre&gt;

&lt;p&gt;Por defecto la migraci&amp;oacute;n crea un campo &lt;code&gt;username&lt;/code&gt;, que no queremos porque ya tenemos el &lt;code&gt;email&lt;/code&gt;, as&amp;iacute; que dejaremos esa l&amp;iacute;nea comentada.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/db/migrate/20110914221626_sorcery_core.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class SorceryCore &amp;lt; ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      # t.string :username,         :null =&amp;gt; false  
      t.string :email,            :default =&amp;gt; nil 
      t.string :crypted_password, :default =&amp;gt; nil
      t.string :salt,             :default =&amp;gt; nil
      t.timestamps
    end
  end
end&lt;/pre&gt;

&lt;p&gt;A continuaci&amp;oacute;n tenemos que configurar Sorcery para que utilice &lt;code&gt;email&lt;/code&gt; en lugar de &lt;code&gt;username&lt;/code&gt;.  Esto se hace modificando el c&amp;oacute;digo de inicializaci&amp;oacute;n de Sorcery.  En la parte superior de este archivo tenemos que especificar los m&amp;oacute;dulos que queremos activar, como adem&amp;aacute;s de &lt;code&gt;core&lt;/code&gt; estamos usando &lt;code&gt;remember_me&lt;/code&gt; ser&amp;aacute; este el &amp;uacute;nico que tenemos que a&amp;ntilde;adir.&lt;/p&gt;

&lt;pre class="codeFilePath"&gt;/config/initializers/sorcery.rb&lt;/pre&gt;
&lt;pre class="ruby"&gt;# The first thing you need to configure is which modules you need in your app.
# The default is nothing which will include only core features (password encryption, login/logout).
# Available submodules are: :user_activation, :http_basic_auth, :remember_me, 
# :reset_password, :session_timeout, :brute_force_protection, :activity_logging, :external
Rails.application.config.sorcery.submodules = [:remember_me]

# Rest of file omitted.&lt;/pre&gt;

&lt;p&gt;Hay otras muchas opciones de configuraci&amp;oacute;n que podemos activar, documentadas en el mismo archivo.  La mayor&amp;iacute;a no tendremos que tocarlas pero una que s&amp;iacute; que tenemos que cambiar es  &lt;code&gt;username_attribute_name&lt;/code&gt;.   Activaremos esta opci&amp;oacute;n y cambiaremos su valor para que sea  &lt;code&gt;:email&lt;/code&gt; dado que ese es el campo que queremos usar para identificar a los usuarios.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/initializers/sorcery.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;config.user_config do |user|
  # -- core --
  user.username_attribute_name = :email                                          
	# change default username
	# attribute, for example, 
	# to use :email as the login.                                                                                                                                                                          

	# Other options omitted.
end
# This line must come after the &amp;#x27;user config&amp;#x27; block.
config.user_class = &amp;quot;User&amp;quot;                                                          	
# define which model authenticates                                                                   	
# with sorcery.
end&lt;/pre&gt;

&lt;p&gt;Al final del archivo existe un valor de configuraci&amp;oacute;n que especifica el nombre del modelo que Sorcery utiliza para la autenticaci&amp;oacute;n y que por defecto es  &lt;code&gt;User&lt;/code&gt;.   Como nuestra aplicaci&amp;oacute;n todav&amp;iacute;a no tiene un modelo para los usuarios tenemos que crearlo, pero dado que ya tenemos la migraci&amp;oacute;n creada con los campos que Sorcery necesita tendremos que decirle a Rails que para este nuevo modelo no genere  migraci&amp;oacute;n.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g model user --skip-migration&lt;/pre&gt;

&lt;p&gt;Tan s&amp;oacute;lo tenemos que a&amp;ntilde;adir esta l&amp;iacute;nea de c&amp;oacute;digo para activar Sorcery en el modelo &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class User &amp;lt; ActiveRecord::Base
  authenticates_with_sorcery!
end&lt;/pre&gt;

&lt;p&gt;Esta l&amp;iacute;nea a&amp;ntilde;ade varios m&amp;eacute;todos al modelo &lt;code&gt;User&lt;/code&gt; que sirven para gestionar la autenticaci&amp;oacute;n.  Sin embargo no a&amp;ntilde;ade validaciones o protege ning&amp;uacute;n atributo, esta tarea nos corresponde a nosotros.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/app/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class User &amp;lt; ActiveRecord::Base
  authenticates_with_sorcery!
  
  attr_accessible :email, :password, :password_confirmation
  
  validates_confirmation_of :password
  validates_presence_of :password, :on =&amp;gt; :create
  validates_presence_of :email
  validates_uniqueness_of :email
end&lt;/pre&gt;

&lt;p&gt;Ya podemos lanzar las migraciones para que se cree la tabla de usuarios.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rake db:migrate&lt;/pre&gt;

&lt;h3&gt;Controladores y vistas&lt;/h3&gt;

&lt;p&gt;Ahora que hemos configurado el modelo &lt;code&gt;User&lt;/code&gt; debemos generar algunos controladores que lo acompa&amp;ntilde;en.  Primero crearemos el &lt;code&gt;UsersController&lt;/code&gt; para gestionar el proceso de alta.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g controller users new&lt;/pre&gt;

&lt;p&gt;Nos har&amp;aacute; falta tambi&amp;eacute;n un &lt;code&gt;SessionsController&lt;/code&gt; para controlar los inicios de sesi&amp;oacute;n.&lt;/p&gt;
  
&lt;pre class="terminal"&gt;$ rails g controller sessions new&lt;/pre&gt;

&lt;p&gt;Todo esto es muy parecido a como hicimos en el episodio 250 cuando creamos la autenticaci&amp;oacute;n desde cero, por lo que aqu&amp;iacute; iremos m&amp;aacute;s deprisa.  El controlador &lt;code&gt;UsersController&lt;/code&gt; ser&amp;aacute; bastante normal, creando un nuevo &lt;code&gt;User&lt;/code&gt; en la acci&amp;oacute;n &lt;code&gt;new&lt;/code&gt; y creando un nuevo &lt;code&gt;User&lt;/code&gt; a partir de los par&amp;aacute;metros recibidos en la acci&amp;oacute;n &lt;code&gt;create&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/users_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class UsersController &amp;lt; ApplicationController
  def new
    @user = User.new
  end
  
  def create
    @user = User.new(params[:user])
    if @user.save
      redirect_to root_url, :notice =&amp;gt; &amp;quot;Signed up!&amp;quot;
    else
      render :new
    end
  end
end&lt;/pre&gt;

&lt;p&gt;No habr&amp;aacute; sorpresas con la plantilla para &lt;code&gt;new&lt;/code&gt; que es tan s&amp;oacute;lo un formulario para crear un usuario con campos llamados  &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt; y &lt;code&gt;password_confirmation&lt;/code&gt; as&amp;iacute; como el c&amp;oacute;digo que muestra los errores de validaci&amp;oacute;n.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/users/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;h1&amp;gt;Sign Up&amp;lt;/h1&amp;gt;

&amp;lt;%= form_for @user do |f| %&amp;gt;
  &amp;lt;% if @user.errors.any? %&amp;gt;
    &amp;lt;div class=&amp;quot;error_messages&amp;quot;&amp;gt;
      &amp;lt;h2&amp;gt;Form is invalid&amp;lt;/h2&amp;gt;
      &amp;lt;ul&amp;gt;
        &amp;lt;% for message in @user.errors.full_messages %&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;%= message %&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;% end %&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;% end %&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= f.label :email %&amp;gt;
    &amp;lt;%= f.text_field :email %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= f.label :password %&amp;gt;
    &amp;lt;%= f.password_field :password %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= f.label :password_confirmation %&amp;gt;
    &amp;lt;%= f.password_field :password_confirmation %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;actions&amp;quot;&amp;gt;&amp;lt;%= f.submit %&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/pre&gt;

&lt;p&gt;La cosa se pone m&amp;aacute;s interesante con &lt;code&gt;SessionsController&lt;/code&gt;.  Tambi&amp;eacute;n tenemos una acci&amp;oacute;n &lt;code&gt;new&lt;/code&gt; donde no hace falta a&amp;ntilde;adir m&amp;aacute;s c&amp;oacute;digo as&amp;iacute; que pasaremos directamente a la plantilla donde nos hace falta poner un formulario de inicio de sesi&amp;oacute;n con los campos &lt;code&gt;email&lt;/code&gt; y &lt;code&gt;password&lt;/code&gt; as&amp;iacute; como un &lt;code&gt;checkbox&lt;/code&gt; para el campo &lt;code&gt;remember_me&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/sessions/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;h1&amp;gt;Log in&amp;lt;/h1&amp;gt;

&amp;lt;%= form_tag sessions_path do %&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= label_tag :email %&amp;gt;
    &amp;lt;%= text_field_tag :email, params[:email] %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= label_tag :password %&amp;gt;
    &amp;lt;%= password_field_tag :password %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= check_box_tag :remember_me, 1, params[:remember_me] %&amp;gt;
    &amp;lt;%= label_tag :remember_me %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;actions&amp;quot;&amp;gt;&amp;lt;%= submit_tag &amp;quot;Log in&amp;quot; %&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Tenemos que escribir la acci&amp;oacute;n &lt;code&gt;create&lt;/code&gt; para procesar el formulario de inicio de sesi&amp;oacute;n.  Sorcery nos da un m&amp;eacute;todo llamado &lt;code&gt;login&lt;/code&gt; que recibe tres par&amp;aacute;metros: un nombre de usuario o direcci&amp;oacute;n de correo, la clave introducida y el valor de la casilla &lt;code&gt;remember_me&lt;/code&gt;.  Este m&amp;eacute;todo realizar&amp;aacute; la autenticaci&amp;oacute;n y devolver&amp;aacute; un &lt;code&gt;User&lt;/code&gt; si es que se ha encontrado uno que coincida.  Podemos comprobarlo y redirigir a la p&amp;aacute;gina pricipal en ese caso, y si no mostrar un mensaje de error junto con el formulario de inicio de sesi&amp;oacute;n.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/controllers/sessions_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class SessionsController &amp;lt; ApplicationController
  def new
  end
  
  def create
    user = login(params[:email], params[:password], &amp;crarr;
      params[:remember_me])
    if user
      redirect_back_or_to root_url, :notice =&amp;gt; &amp;quot;Logged in!&amp;quot;
    else
      flash.now.alert = &amp;quot;Email or password was invalid.&amp;quot;
    end
  end
end&lt;/pre&gt;

&lt;p&gt;En lugar de utilizar &lt;code&gt;redirect_to&lt;/code&gt; para llevar al usuario a la p&amp;aacute;gina principal cuando &amp;eacute;ste se autentica correctamente, utilizaremos un m&amp;eacute;todo de Sorcery llamado &lt;code&gt;redirect_back_or_to&lt;/code&gt; que se comporta de forma similar a &lt;code&gt;redirect_to&lt;/code&gt; pero con la diferencia de que si Sorcery ha guardado una URL redirigir&amp;aacute; a esta en lugar de a la que se haya especificado en el c&amp;oacute;digo.  Esto es muy &amp;uacute;til porque si exigimos que el usuario inicie sesi&amp;oacute;n cuando visite cierta p&amp;aacute;gina, Sorcery lo llevar&amp;aacute; autom&amp;aacute;ticamente a esa p&amp;aacute;gina cuando se autentique correctamente.&lt;/p&gt;

&lt;p&gt;Todav&amp;iacute;a nos hace falta la manera de que el usuario cierre la sesi&amp;oacute;n, as&amp;iacute; que a&amp;ntilde;adiremos la acci&amp;oacute;n &lt;code&gt;destroy&lt;/code&gt; al controlador.  Sorcery tiene el m&amp;eacute;todo &lt;code&gt;logout&lt;/code&gt;, que es todo lo que tenemos que llamar para cerrar dicha sesi&amp;oacute;n.  Tras esto redirigimos al usuario a la portada del sitio web.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/controllers/sessions_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def destroy
  logout
  redirect_to root_url, :notice =&amp;gt; &amp;quot;Logged out!&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;A continuaci&amp;oacute;n nos iremos al fichero de rutas y ajustaremos todos los cables, cambiando las acciones que han sido generadas autom&amp;aacute;ticamente y poniendo estas rutas:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;Auth::Application.routes.draw do
  get &amp;quot;logout&amp;quot; =&amp;gt; &amp;quot;sessions#destroy&amp;quot;, :as =&amp;gt; &amp;quot;logout&amp;quot;
  get &amp;quot;login&amp;quot; =&amp;gt; &amp;quot;sessions#new&amp;quot;, :as =&amp;gt; &amp;quot;login&amp;quot;
  get &amp;quot;signup&amp;quot; =&amp;gt; &amp;quot;users#new&amp;quot;, :as =&amp;gt; &amp;quot;signup&amp;quot;
  resources :users
  resources :sessions
  get &amp;quot;secret&amp;quot; =&amp;gt; &amp;quot;home#secret&amp;quot;, :as =&amp;gt; &amp;quot;secret&amp;quot;
  root :to =&amp;gt; &amp;quot;home#index&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Con esto ya tenemos varias rutas y un par de recursos con los que podemos gestionar toda la funcionalidad relacionada con la autenticaci&amp;oacute;n.&lt;/p&gt;

&lt;p&gt;Con estas nuevas p&amp;aacute;ginas implementadas s&amp;oacute;lo nos falta poner los enlaces para que los usuarios puedan llegar a ellas.  Los a&amp;ntilde;adiremos en la p&amp;aacute;gina de &lt;em&gt;layout&lt;/em&gt; para que sean visibles en toda la aplicaci&amp;oacute;n.  Podemos usar el m&amp;eacute;todo  &lt;code&gt;current_user&lt;/code&gt; para ver si tenemos una sesi&amp;oacute;n iniciada en cuyo caso mostraremos la direcci&amp;oacute;n de correo y el enlace para salir de la sesi&amp;oacute;n.  Si no hay usuario mostraremos los enlaces a las p&amp;aacute;ginas de alta y de inicio de sesi&amp;oacute;n.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;Auth Example&amp;lt;/title&amp;gt;
  &amp;lt;%= stylesheet_link_tag    &amp;quot;application&amp;quot; %&amp;gt;
  &amp;lt;%= javascript_include_tag &amp;quot;application&amp;quot; %&amp;gt;
  &amp;lt;%= csrf_meta_tags %&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body class=&amp;quot;&amp;lt;%= params[:controller] %&amp;gt;&amp;quot;&amp;gt;
  &amp;lt;div id=&amp;quot;container&amp;quot;&amp;gt;
    &amp;lt;div class=&amp;quot;user_nav&amp;quot;&amp;gt;
      &amp;lt;% if current_user %&amp;gt;
        Logged in as &amp;lt;%= current_user.email %&amp;gt;.
        &amp;lt;%= link_to &amp;quot;Log out&amp;quot;, logout_path %&amp;gt;
      &amp;lt;% else %&amp;gt;
        &amp;lt;%= link_to &amp;quot;Sign up&amp;quot;, signup_path %&amp;gt; or
        &amp;lt;%= link_to &amp;quot;Log in&amp;quot;, login_path  %&amp;gt;.
      &amp;lt;% end %&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;% flash.each do |name, msg| %&amp;gt;
      &amp;lt;%= content_tag :div, msg, :id =&amp;gt; &amp;quot;flash_#{name}&amp;quot; %&amp;gt;
    &amp;lt;% end %&amp;gt;
    &amp;lt;%= yield %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;

&lt;p&gt;Con esto ya est&amp;aacute; todo listo y podemos comprobar el sitio.  Si vamos a la p&amp;aacute;gina principal veremos los enlaces de registro y de inicio de sesi&amp;oacute;n.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/731/original/E283I02.png" width="798" height="380" alt="En todas las p&#225;ginas salen los enlaces de registro e inicio de sesi&#243;n."/&gt;
&lt;/div&gt;

&lt;p&gt;Si hacemos clic en  &amp;ldquo;Sign up&amp;rdquo; veremos el formulario de registro donde podemos darnos de alta.  Luego podemos hacer clic en &amp;ldquo;Log in&amp;rdquo; para entrar con nuestros datos de inicio de sesi&amp;oacute;n.&lt;/p&gt;
 
&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/732/original/E283I03.png" width="803" height="397" alt="Inicio de sesi&#243;n."/&gt;
&lt;/div&gt;

&lt;h3&gt;Autorizaci&amp;oacute;n&lt;/h3&gt;

&lt;p&gt;Ahora que tenemos la sesi&amp;oacute;n iniciada ya podemos visitar la p&amp;aacute;gina secreta.  Pero si cerramos la sesi&amp;oacute;n y visitamos la p&amp;aacute;gina secreta veremos que seguimos pudiendo acceder a ella.  Nos hace falta implementar la autorizaci&amp;oacute;n necesaria para que la p&amp;aacute;gina s&amp;oacute;lo pueda ser accedida por usuarios con sesi&amp;oacute;n iniciada.&lt;/p&gt;

&lt;p&gt;La p&amp;aacute;gina secreta es una acci&amp;oacute;n de &lt;code&gt;HomeController&lt;/code&gt;.  Para limitar el acceso a las acciones podemos utilizar un &lt;code&gt;before_filter&lt;/code&gt; de Sorcery llamado &lt;code&gt;require_login&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/home_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class HomeController &amp;lt; ApplicationController
  before_filter :require_login, :only =&amp;gt; :secret

  def index
  end

  def secret
  end
end&lt;/pre&gt;

&lt;p&gt;Cuando se activa este filtro Sorcery llama a su m&amp;eacute;todo &lt;code&gt;not_authenticated&lt;/code&gt;, que podemos redefinir en &lt;code&gt;ApplicationController&lt;/code&gt; para poder controlar lo que ocurre cuando falla la autorizaci&amp;oacute;n.  De momento nosotros optaremos por dirigir a la p&amp;aacute;gina de inicio de sesi&amp;oacute;n y mostrar un mensaje de alerta.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/application_controller.rb&lt;/p&gt;
&lt;pre class="rubby"&gt;class ApplicationController &amp;lt; ActionController::Base
  protect_from_forgery
  
  private
  def not_authenticated
    redirect_to login_url, :alert =&amp;gt; &amp;quot;First log in to view &amp;crarr;
    this page.&amp;quot;
  end
  
end&lt;/pre&gt;

&lt;p&gt;Si intentamos visitar la p&amp;aacute;gina secreta sin una sesi&amp;oacute;n abierta seremos llevados a la p&amp;aacute;gina de inicio de sesi&amp;oacute;n, mostr&amp;aacute;ndose un mensaje de alerta.&lt;/p&gt;


&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/733/original/E283I04.png" width="803" height="436" alt="Se nos lleva a la p&#225;gina de inicio de sesi&#243;n al tratar de acceder a la p&#225;gina secreta sin sesi&#243;n iniciada."/&gt;
&lt;/div&gt;

&lt;p&gt;Tras iniciar la sesi&amp;oacute;n volveremos a la p&amp;aacute;gina secreta porque Sorcery recordar&amp;aacute; la p&amp;aacute;gina a la que est&amp;aacute;bamos tratando de acceder cuando nos llev&amp;oacute; al inicio de sesi&amp;oacute;n.&lt;/p&gt;


&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/734/original/E283I05.png" width="803" height="436" alt="Ya podemos ver la p&#225;gina tras iniciar la sesi&#243;n."/&gt;
&lt;/div&gt;

&lt;p&gt;Con esto terminamos nuestro episodio sobre Sorcery.  Tiene muchas m&amp;aacute;s funciones que hoy no hemos visto pero que se pueden encontrar en su &lt;a href="https://github.com/NoamB/sorcery"&gt;documentaci&amp;oacute;n&lt;/a&gt;. Puede que nos merezca la pena considerar Sorcery  si buscamos una soluci&amp;oacute;n de autenticaci&amp;oacute;n que trabaje a un nivel un poco m&amp;aacute;s bajo que otras gemas.&lt;/p&gt;
</description>
      <pubDate>Sun, 16 Oct 2011 22:16:54 +0000</pubDate>
      <guid>http://es.asciicasts.com/episodes/283-autenticacion-usando-sorcery</guid>
      <link>http://es.asciicasts.com/episodes/283-autenticacion-usando-sorcery</link>
    </item>
    <item>
      <title>Actualizaci&#243;n a Rails 3.1</title>
      <description>&lt;p&gt;Ya ha salido por fin Rails 3.1.  Podemos leer un repaso de sus nuevas funcionalidades en las   &lt;a href="http://guides.rubyonrails.org/3_1_release_notes.html"&gt;Notas de Lanzamiento en el sitio RailsGuides&lt;/a&gt;, algunas de las cuales ya han sido estudiadas en &lt;a href="http://railscasts.com/?tag_id=31"&gt;Railscasts&lt;/a&gt; y &lt;a href="http://es.asciicasts.com/tags/rails-31"&gt;aqu&amp;iacute; mismo&lt;/a&gt;. En este episodio nos centraremos en el proceso de actualizaci&amp;oacute;n de una aplicaci&amp;oacute;n Rails 3.0 a la versi&amp;oacute;n 3.1, y a modo de ejemplo veremos c&amp;oacute;mo se ha migrado el sitio Railscasts.&lt;/p&gt;

&lt;h3&gt;Preparativos&lt;/h3&gt;

&lt;p&gt;Antes de acometer la actualizaci&amp;oacute;n a Rails 3.1 tenemos que dar algunos pasos previos.  Si el sitio no est&amp;aacute; funcionando en la &amp;uacute;ltima versi&amp;oacute;n de Rails 3.0 (a d&amp;iacute;a de hoy es la 3.0.10) tendremos que actualizarlo.  Esto lo podemos hacer escribiendo la versi&amp;oacute;n en el Gemfile y luego ejecutando &lt;code&gt;bundle&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;gem &amp;quot;rails&amp;quot;, &amp;quot;3.0.10&amp;quot;&lt;/pre&gt;

&lt;p&gt;Lo siguiente que haremos es pasar la bater&amp;iacute;a de tests de la aplicaci&amp;oacute;n para comprobar que todos siguen pasando y que no aparecen mensajes de aviso de fin de soporte.  Si los hubiera tendremos que corregirlos antes de continuar.  En el caso del c&amp;oacute;digo de Railscasts no hay estos problemas as&amp;iacute; que continuaremos con la actualizaci&amp;oacute;n.&lt;/p&gt;

&lt;h3&gt;Actualizaci&amp;oacute;n&lt;/h3&gt;

&lt;p&gt;Ya estamos listos para empezar con la actualizaci&amp;oacute;n, que haremos dentro de una nueva rama Git llamada &lt;code&gt;rails31&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ git checkout -b rails31&lt;/pre&gt;

&lt;p&gt;La actualizaci&amp;oacute;n a Rails 3.1 es muy sencilla, s&amp;oacute;lo tenemos que ir al &lt;code&gt;Gemfile&lt;/code&gt; de nuestra aplicaci&amp;oacute;n y cambiar la versi&amp;oacute;n a la &amp;uacute;ltima versi&amp;oacute;n de 3.1 (que ahora mismo es la &lt;code&gt;3.1.0.&lt;/code&gt;).&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;gem &amp;quot;rails&amp;quot;, &amp;quot;3.1.0&amp;quot;&lt;/pre&gt;

&lt;p&gt;Ahora ya podemos ejecutar &lt;code&gt;bundle update&lt;/code&gt; para instalar la nueva versi&amp;oacute;n.  El pr&amp;oacute;ximo cambio que tenemos que hacer es en el fichero de configuraci&amp;oacute;n &lt;code&gt;development.rb&lt;/code&gt; donde tenemos que quitar o comentar la siguiente l&amp;iacute;nea:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/development.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# config.action_view.debug_rjs = true&lt;/pre&gt;

&lt;p&gt;Si lanzamos ahora los tests veremos que siguen pasando.  Podemos incluso arrancar el servidor Rails y cargar la aplicaci&amp;oacute;n en el navegador.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/728/original/E282I01.png" width="802" height="567" alt="La aplicaci&#243;n funciona bajo Rails 3.1"/&gt;
&lt;/div&gt;

&lt;h3&gt;Cambios en la aplicaci&amp;oacute;n para usar el conducto de est&amp;aacute;ticos&lt;/h3&gt;

&lt;p&gt;El conducto de est&amp;aacute;ticos es una de las funcionalidades m&amp;aacute;s importantes en Rails 3.1 pero por ahora nuestra aplicaci&amp;oacute;n no lo tiene en cuenta y aloja sus im&amp;aacute;genes en el directorio &lt;code&gt;/public&lt;/code&gt;. Esta funcionalidad es totalmente opcional y no tiene ning&amp;uacute;n efecto hasta que la activemos por lo que si no podemos o queremos usar el conducto de est&amp;aacute;ticos no tenemos por qu&amp;eacute; quedarnos sin migrar a Rails 3.1.&lt;/p&gt;

&lt;p&gt;Si nos interesa usar el conducto de est&amp;aacute;ticos debemos a&amp;ntilde;adir las siguientes l&amp;iacute;neas al &lt;code&gt;Gemfile&lt;/code&gt; (son las que se generar&amp;iacute;an autom&amp;aacute;ticamente si empez&amp;aacute;semos con una aplicaci&amp;oacute;n Rails 3.1 desde cero).&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;# Gems used only for assets and not required
# in production environments by default.
group :assets do
  gem &amp;#x27;sass-rails&amp;#x27;, &amp;quot; ~&amp;gt; 3.1.0&amp;quot;
  gem &amp;#x27;coffee-rails&amp;#x27;, &amp;quot; ~&amp;gt; 3.1.0&amp;quot;
  gem &amp;#x27;uglifier&amp;#x27;
end

gem &amp;#x27;jquery-rails&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Este c&amp;oacute;digo crea un grupo &lt;code&gt;assets&lt;/code&gt; e instala varias gemas relacionadas con los est&amp;aacute;ticos. Tambi&amp;eacute;n incluye la gema &lt;code&gt;jquery-rails&lt;/code&gt; para que podamos usar jQuery (los que prefieran usar Prototype pueden usar  &lt;a href="https://github.com/rails/prototype-rails"&gt;&lt;code&gt;prototype-rails&lt;/code&gt;&lt;/a&gt;). Tambi&amp;eacute;n tenemos que modificar  &lt;code&gt;/config/application.rb&lt;/code&gt;, quitando este c&amp;oacute;digo:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/application.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# If you have a Gemfile, require the gems listed there, including any gems
# you&amp;#x27;ve limited to :test, :development, or :production.
Bundler.require(:default, Rails.env) if defined?(Bundler)&lt;/pre&gt;

&lt;p&gt;Y escribiendo este otro:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/application.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;if defined?(Bundler)
  # If you precompile assets before deploying to production, 
    use this line
  Bundler.require *Rails.groups(:assets =&amp;gt; %w(development test))
  # If you want your assets lazily compiled in production, 
    use this line
  # Bundler.require(:default, :assets, Rails.env)
end&lt;/pre&gt;

&lt;p&gt;El c&amp;oacute;digo a&amp;ntilde;ade el grupo &lt;code&gt;assets&lt;/code&gt; a los grupos sobre los que Bundler har&amp;aacute; un &lt;code&gt;require&lt;/code&gt;.  Aqu&amp;iacute; se efect&amp;uacute;a tambi&amp;eacute;n la activaci&amp;oacute;n propiamente dicha del conducto de est&amp;aacute;ticos, dentro de la clase &lt;code&gt;Application&lt;/code&gt;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/application.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# Enable the asset pipeline
config.assets.enabled = true

# Version of your assets, change this if you want to expire all your assets
config.assets.version = &amp;#x27;1.0&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Este c&amp;oacute;digo activa el conducto de est&amp;aacute;ticos y genera un n&amp;uacute;mero de versi&amp;oacute;n, que podremos cambiar para expirar los recursos est&amp;aacute;ticos.&lt;/p&gt;


&lt;p&gt;Debemos cambiar tambi&amp;eacute;n los valores de configuraci&amp;oacute;n en el fichero de configuraci&amp;oacute;n de cada entorno.  Empecemos por &lt;code&gt;development.rb&lt;/code&gt;.  Tenemos que hacer aqu&amp;iacute; un par de cambios para permitir la depuraci&amp;oacute;n:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/environments/development.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;  # Do not compress assets
  config.assets.compress = false
  
  # Expands the lines which load the assets
  config.assets.debug = true&lt;/pre&gt;

&lt;p&gt;El siguiente es  &lt;code&gt;production.rb&lt;/code&gt;.&lt;/p&gt;  

&lt;p class="codeFilePath"&gt;/config/environments/production.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# Compress JavaScript and CSS
config.assets.compress = true
   
# Don&amp;#x27;t fallback to assets pipeline
config.assets.compile = false
   
# Generate digests for assets URLs
config.assets.digest = true&lt;/pre&gt;

&lt;p&gt;En producci&amp;oacute;n nos interesa comprimir los est&amp;aacute;ticos, pero como &amp;eacute;stos ir&amp;aacute;n precompilados pondremos &lt;code&gt;compile&lt;/code&gt; a &lt;code&gt;false&lt;/code&gt;.  Tambi&amp;eacute;n estableceremos &lt;code&gt;digest&lt;/code&gt; a &lt;code&gt;true&lt;/code&gt; para que las URLs  &lt;a href="http://guides.rubyonrails.org/asset_pipeline.html#what-is-fingerprinting-and-why-should-i-care"&gt;lleven su propia huella&lt;/a&gt;.  Estas opciones se pueden configurar de forma diferente para adaptarse al funcionamiento de nuestra aplicaci&amp;oacute;n en producci&amp;oacute;n.&lt;/p&gt;

&lt;p&gt;Por &amp;uacute;ltimo modificaremos el entorno de pruebas.  Aqu&amp;iacute; a&amp;ntilde;adiremos opciones de forma que los recursos est&amp;aacute;ticos se sirvan y guarden en cach&amp;eacute;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/environments/test.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# Configure static asset server for tests with Cache-Control for performance
config.serve_static_assets = true
config.static_cache_control = &amp;quot;public, max-age=3600&amp;quot;

# Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets
config.assets.allow_debugging = true&lt;/pre&gt; 

&lt;p&gt;Si utilizamos Git para llevar el control de versiones en nuestra aplicaci&amp;oacute;n deber&amp;iacute;amos modificar el fichero &lt;code&gt;.gitignore&lt;/code&gt; y a&amp;ntilde;adir el directorio &lt;code&gt;.sass-cache&lt;/code&gt; al listado de elementos ignorados porque no nos interesar&amp;aacute; guardar en Git la cach&amp;eacute; de SASS.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/.gitignore&lt;/p&gt;
&lt;pre class="ruby"&gt;.sass-cache/&lt;/pre&gt;

&lt;h3&gt;Cambio de sitio de los est&amp;aacute;ticos&lt;/h3&gt;

&lt;p&gt;Ahora que ya tenemos el conducto listo, debemos crear el directorio &lt;code&gt;app/assets&lt;/code&gt; para mover all&amp;iacute; los directorios &lt;code&gt;images&lt;/code&gt;, &lt;code&gt;javascripts&lt;/code&gt; y &lt;code&gt;stylesheets&lt;/code&gt; que ten&amp;iacute;amos en &lt;code&gt;/public&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ mkdir app/assets
$ mv public/images/ app/assets/
$ mv public/javascripts/ app/assets/
$ mv public/stylesheets/ app/assets/&lt;/pre&gt;

&lt;p&gt;Algunos de estos archivos ya no hacen falta, como por ejemplo los ficheros &lt;code&gt;jquery.js&lt;/code&gt;, &lt;code&gt;jquery.min.js&lt;/code&gt; y &lt;code&gt;rails.js&lt;/code&gt; del directorio &lt;code&gt;javascripts&lt;/code&gt; que ahora vienen incluidos en la gema jQuery as&amp;iacute; que los borraremos.  Tambi&amp;eacute;n es un buen momento para decididr si queremos mover los &lt;em&gt;plugins&lt;/em&gt; de jQuery a &lt;code&gt;lib/assets&lt;/code&gt; o &lt;code&gt;vendor/assets&lt;/code&gt;, como hicimos en el episodio 279  [&lt;a href="http://railscasts.com/episodes/279-understanding-the-asset-pipeline"&gt;verlo&lt;/a&gt;, &lt;a href="http://es.asciicasts.com/episodes/279-el-conducto-de-estaticos"&gt;leerlo&lt;/a&gt;].&lt;/p&gt;

&lt;p&gt;A continuaci&amp;oacute;n debemos crear los manifiestos.   La aplicaci&amp;oacute;n ya tiene su &lt;code&gt;application.js&lt;/code&gt; y &lt;code&gt;application.css&lt;/code&gt; en los directorios necesarios, as&amp;iacute; que no los tenemos que crear.  Empezaremos con el fichero CSS.  Para convertirlo en un manifiesto tenemos que a&amp;ntilde;adir algunos comentarios en la parte superior para indicarle a  &lt;a href="https://github.com/sstephenson/sprockets"&gt;Sprockets&lt;/a&gt; los ficheros que debe incluir.  Nosotros le diremos que incluya el resto del fichero y el resto de archivos que residan en el directorio &lt;code&gt;stylesheets&lt;/code&gt; y sus subdirectorios.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/application.css&lt;/p&gt;
&lt;pre class="css"&gt;/*
*= require_self
*= require_tree .
*/

/* rest of file omitted */&lt;/pre&gt;

&lt;p&gt;Podemos hacer lo mismo en el fichero &lt;code&gt;application.js&lt;/code&gt;, pero para incluir jQuery tenemos que hacerlo de forma un poco diferente:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/javascripts/application.js&lt;/p&gt;
&lt;pre class="javascript"&gt;//= require jquery
//= require jquery_ujs
//= require_self
//= require_tree .

/* rest of file omitted */&lt;/pre&gt;

&lt;p&gt;De nuevo haremos &lt;code&gt;require_self&lt;/code&gt; porque el propio fichero contendr&amp;aacute; su c&amp;oacute;digo y tambi&amp;eacute;n &lt;code&gt;require_tree&lt;/code&gt; para incluir el resto de los ficheros del directorio.&lt;/p&gt;

&lt;p&gt;Tambi&amp;eacute;n tenemos que ir al fichero &lt;em&gt;layout&lt;/em&gt; y cambiar las l&amp;iacute;neas que incluyen las hojas de estilo y los ficheros de JavaScript de forma que s&amp;oacute;lo hagan referencia al fichero relevante, porque los otros los incluir&amp;aacute; el manifiesto.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;%= stylesheet_link_tag &amp;quot;application&amp;quot; %&amp;gt;
&amp;lt;%= javascript_include_tag &amp;quot;application&amp;quot;, &amp;quot;http://cdn.sublimevideo.net/js/3s7oes9q.js&amp;quot; %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Nuestro JavaScript necesita incluir un fichero externo que no se encontrar&amp;aacute; en el conducto de est&amp;aacute;ticos por lo que debemos seguir incluy&amp;eacute;ndolo en la primera l&amp;iacute;nea.&lt;/p&gt;

&lt;p&gt;Ya podemos probar la aplicaci&amp;oacute;n en el navegador para ver si nuestros cambios funcionan, pero antes debemos ejecutar &lt;code&gt;bundle&lt;/code&gt; para instalar todas las gemas necesarias.  Tras esto podemos arrancar el servidor.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails s&lt;/pre&gt;

&lt;p&gt;Funciona casi todo pero quedan algunas im&amp;aacute;genes rotas, por ejemplo el logo en la parte superior.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/729/original/E282I02.png" width="804" height="381" alt="El sitio funciona pero quedan im&#225;genes rotas."/&gt;
&lt;/div&gt;

&lt;p&gt;El problema es que la URL de la imagen ha sido escrita a fuego en el fichero de &lt;em&gt;layout&lt;/em&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;img src=&amp;quot;/images/railscasts_logo.png&amp;quot; width=&amp;quot;423&amp;quot; height=&amp;quot;56&amp;quot; alt=&amp;quot;RailsCasts = Ruby on Rails Screencasts&amp;quot;/&amp;gt;&lt;/pre&gt;

&lt;p&gt;Esto no funciona porque las im&amp;aacute;genes de nuestra aplicaci&amp;oacute;n ya no se alojan en &lt;code&gt;/public/images&lt;/code&gt;.  La soluci&amp;oacute;n m&amp;aacute;s sencilla ser&amp;iacute;a cambiar la URL por  &lt;code&gt;/assets/railscasts_logo.png&lt;/code&gt; pero tendremos problemas en producci&amp;oacute;n.  Si tenemos la opci&amp;oacute;n &lt;code&gt;assets.digest&lt;/code&gt; se a&amp;ntilde;adir&amp;aacute; una huella al final del nombre de forma que no nos bastar&amp;aacute; con tener una referencia est&amp;aacute;tica a este fichero.  Deber&amp;iacute;amos siempre utilizar los m&amp;eacute;todos &lt;em&gt;helper&lt;/em&gt; para enlazar correctamente la imagen en desarrollo y producci&amp;oacute;n:&lt;/p&gt;
&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;%= image_tag(&amp;quot;railscasts_logo.png&amp;quot;, :size =&amp;gt; &amp;quot;423x56&amp;quot;, :alt =&amp;gt; &amp;quot;RailsCasts - Ruby on Rails Screencasts&amp;quot;) %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Tenemos que buscar globalmente en nuestra aplicaci&amp;oacute;n y cambiar todos los est&amp;aacute;ticos que est&amp;eacute;n referenciados a mano para pasar a usar los &lt;em&gt;helpers&lt;/em&gt; de Rails como con la imagen anterior.  Si ahora recargamos la p&amp;aacute;gina y vemos el logo esto querr&amp;aacute; decir que el conducto de est&amp;aacute;ticos funciona correctamente.&lt;/p&gt;

&lt;p&gt;Con esto hemos terminado la actualizaci&amp;oacute;n a Rails 3.1 de nuestra aplicaci&amp;oacute;n.  Hay otras funcionalidades extra de las que nos podemos aprovechar y que se pueden consultar en el resto de episodios dedicados a Rails 3.1 por si nos fueran de utilidad en nuestras aplicaciones.&lt;/p&gt;
</description>
      <pubDate>Sun, 18 Sep 2011 21:21:42 +0000</pubDate>
      <guid>http://es.asciicasts.com/episodes/282-actualizacion-a-rails-31</guid>
      <link>http://es.asciicasts.com/episodes/282-actualizacion-a-rails-31</link>
    </item>
    <item>
      <title>Foreman</title>
      <description>&lt;p&gt;Hace poco Ryan Bates pregunt&amp;oacute; en Twitter cu&amp;aacute;l es la mejor manera de gestionar los procesos en segundo plano que necesita una aplicaci&amp;oacute;n Rails en desarrollo.  En este episodio veremos la soluci&amp;oacute;n que le propusieron varios lectores:  &lt;a href="https://github.com/ddollar/foreman"&gt;Foreman&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Por ejemplo, para la aplicaci&amp;oacute;n  &lt;a href="https://github.com/ryanb/govsgo"&gt;GoVsGo&lt;/a&gt; en desarrollo tenemos que lanzar de antemano varios procesos en segundo plano: Beanstalkd, un proceso &lt;code&gt;script/worker&lt;/code&gt; y un servidor Faye.  Tenemos que arrancar todo esto cada vez que queramos usar la aplicaci&amp;oacute;n en desarrollo, as&amp;iacute; que ser&amp;iacute;a mucho mejor si hubiera una forma m&amp;aacute;s sencilla de gestionar todos estos procesos.  Aqu&amp;iacute; es donde interviene Foreman.&lt;/p&gt;

&lt;h3&gt;Foreman: instalaci&amp;oacute;n y uso&lt;/h3&gt;

&lt;p&gt;Foreman se instala como es habitual con el resto de gemas.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ gem install foreman&lt;/pre&gt;

&lt;p&gt;Foreman lee los procesos que tiene que gestionar a partir de un fichero llamado &lt;code&gt;Procfile&lt;/code&gt; en el directorio de la aplicaci&amp;oacute;n Rails, por lo que primero tenemos que crearlo.  Cada proceso se define mediante un nombre y dos puntos, as&amp;iacute; como la ruta del proceso que queremos ejecutar, por lo que para nuestros tres procesos haremos lo siguiente:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Procfile&lt;/p&gt;
&lt;pre class="ruby"&gt;beanstalk:  beanstalkd
worker:     ./script/worker
faye:       rackup faye.ru -s thin -E production&lt;/pre&gt;

&lt;p&gt;Una vez que hayamos escrito nuestro &lt;code&gt;Procfile&lt;/code&gt; podemos comprobar su validez ejecutando &lt;code&gt;foreman check&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ foreman check
valid procfile detected (beanstalk, worker, faye)&lt;/pre&gt;

&lt;p&gt;Si utilizamos tabuladores en lugar de espacios para separar el nombre del ejecutable propiamente dicho veremos mensajes de aviso, lo que tendremos que tener en cuenta.  Si el fichero es v&amp;aacute;lido podemos ejecutar Foreman con la orden &lt;code&gt;foreman start&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ foreman start
20:06:35 beanstalk.1  | started with pid 23140
20:06:35 worker.1     | started with pid 23141
20:06:35 faye.1       | started with pid 23143
20:06:36 faye.1       | &amp;gt;&amp;gt; Thin web server (v1.2.11 codename Bat-Shit Crazy)
20:06:36 faye.1       | &amp;gt;&amp;gt; Maximum connections set to 1024
20:06:36 faye.1       | &amp;gt;&amp;gt; Listening on 0.0.0.0:9292, CTRL+C to stop
20:06:38 worker.1     | [2011-08-29 20:06:38 +0100] Working 1 jobs: [ Game.move ]&lt;/pre&gt;

&lt;p&gt;Se ejecutar&amp;aacute;n cada uno de los procesos que hayamos especificado en el &lt;code&gt;Procfile&lt;/code&gt; y su salida aparecer&amp;aacute; en el terminal.  Si escribimos &lt;code&gt;CTRL+C&lt;/code&gt; en la ventana de terminal, se parar&amp;aacute;n todos los procesos.&lt;/p&gt;

&lt;p&gt;Foreman dispone de una  &lt;a href="http://ddollar.github.com/foreman/"&gt;p&amp;aacute;gina de manual&lt;/a&gt; que documenta su funcionalidad y las opciones disponibles, algunas de las cuales veremos a continuaci&amp;oacute;n.  Si s&amp;oacute;lo queremos arrancar un proceso podemos pasar su nombre directamente:&lt;/p&gt;

&lt;pre class="terminal"&gt;$ foreman start faye
20:35:41 faye.1       | started with pid 23322
20:35:41 faye.1       | &amp;gt;&amp;gt; Thin web server (v1.2.11 codename Bat-Shit Crazy)
20:35:41 faye.1       | &amp;gt;&amp;gt; Maximum connections set to 1024
20:35:41 faye.1       | &amp;gt;&amp;gt; Listening on 0.0.0.0:9292, CTRL+C to stop&lt;/pre&gt;

&lt;p&gt;Si queremos arrancar m&amp;uacute;ltiples copias de un proceso podemos hacerlo con &lt;code&gt;-c&lt;/code&gt;.  Por ejemplo, podemos ejecutar cuatro procesos en segundo plano de Beanstalk con &lt;code&gt;foreman start -c worker=4&lt;/code&gt;.&lt;/p&gt;


&lt;pre class="terminal"&gt;$ foreman start -c worker=4
20:39:41 beanstalk.1  | started with pid 23366
20:39:41 worker.1     | started with pid 23368
20:39:41 worker.2     | started with pid 23370
20:39:41 worker.3     | started with pid 23372
20:39:41 worker.4     | started with pid 23374
20:39:41 faye.1       | started with pid 23376
20:39:42 faye.1       | &amp;gt;&amp;gt; Thin web server (v1.2.11 codename Bat-Shit Crazy)
20:39:42 faye.1       | &amp;gt;&amp;gt; Maximum connections set to 1024
20:39:42 faye.1       | &amp;gt;&amp;gt; Listening on 0.0.0.0:9292, CTRL+C to stop
20:39:46 worker.3     | [2011-08-29 20:39:46 +0100] Working 1 jobs: [ Game.move ]
20:39:46 worker.1     | [2011-08-29 20:39:46 +0100] Working 1 jobs: [ Game.move ]
20:39:46 worker.2     | [2011-08-29 20:39:46 +0100] Working 1 jobs: [ Game.move ]
20:39:47 worker.4     | [2011-08-29 20:39:47 +0100] Working 1 jobs: [ Game.move ]&lt;/pre&gt;

&lt;h3&gt;Exportaci&amp;oacute;n de procesos&lt;/h3&gt;

&lt;p&gt;Con Foreman disponemos de una orden &lt;code&gt;export&lt;/code&gt; que es &amp;uacute;til para exportar el listado de procesos en formato &lt;code&gt;inittab&lt;/code&gt; o &lt;code&gt;upstart&lt;/code&gt; que podemos utilizar en un servidor de producci&amp;oacute;n.  Si ejecutamos &lt;code&gt;foreman export upstart .&lt;/code&gt; Foreman escribir&amp;aacute; los ficheros de configuraci&amp;oacute;n necesarios para upstart en el directorio actual.  Si le echamos un vistazo veremos que ejecutar&amp;aacute; la orden necesaria para arrancar un servidor &lt;code&gt;beanstalkd&lt;/code&gt;, gestionando correctamente los &lt;em&gt;logs&lt;/em&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/govsgo-beanstalk-1.conf&lt;/p&gt;
&lt;pre class="terminal"&gt;start on starting govsgo-beanstalk
stop on stopping govsgo-beanstalk
respawn

exec su - govsgo -c &amp;#x27;cd /Users/eifion/govsgo; export PORT=5000; beanstalkd &amp;gt;&amp;gt; /var/log/govsgo/beanstalk-1.log 2&amp;gt;&amp;amp;1&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Con esto concluye nuestro episodio sobre Foreman.  Ha sido un poco m&amp;aacute;s breve que de costumbre, pero porque Foreman es una soluci&amp;oacute;n muy sencilla para un problema espec&amp;iacute;fico que hace bien su trabajo.  Si tenemos que arrancar varios procesos para que nuestra aplicaci&amp;oacute;n Rails se encuentre operativa en modo de desarrollo, Foreman es una opci&amp;oacute;n que merece la pena considerar.&lt;/p&gt;
</description>
      <pubDate>Sun, 18 Sep 2011 21:18:48 +0000</pubDate>
      <guid>http://es.asciicasts.com/episodes/281-foreman</guid>
      <link>http://es.asciicasts.com/episodes/281-foreman</link>
    </item>
    <item>
      <title>Pry y Rails</title>
      <description>&lt;p&gt;&lt;a href="http://pry.github.com/"&gt;Pry&lt;/a&gt; es una consola de &amp;oacute;rdenes alternativa a IRB pero con la diferencia de que incluye muchas funcionalidades extra, en este episodio veremos c&amp;oacute;mo funciona y c&amp;oacute;mo la podemos integrar en nuestras aplicaciones Rails.&lt;/p&gt;

&lt;p&gt;Pry se instala f&amp;aacute;cilmente como gema.  Instalaremos tambi&amp;eacute;n la gema &lt;code&gt;pry-doc&lt;/code&gt;, m&amp;aacute;s adelante veremos por qu&amp;eacute;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ gem install pry pry-doc&lt;/pre&gt;

&lt;p&gt;Como estamos usando &lt;em&gt;gemsets&lt;/em&gt; de RVM instalaremos Pry para que est&amp;eacute; disponible globalmente en todos los &lt;em&gt;gemsets&lt;/em&gt; que tengamos.  Esto lo podemos hacer con las siguientes &amp;oacute;rdenes:&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rvm gemset use global
$ gem install pry pry-doc&lt;/pre&gt;

&lt;p&gt;Tras la instalaci&amp;oacute;n de Pry podemos ejecutarlo con &lt;code&gt;pry&lt;/code&gt;.  Como con &lt;code&gt;irb&lt;/code&gt; podemos ejecutar el c&amp;oacute;digo Ruby que queramos.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ pry
pry(main)&amp;gt; 1 + 2
=&amp;gt; 3&lt;/pre&gt;

&lt;p&gt;Pero Pry es mucho m&amp;aacute;s que una simple calculadora.  Antes de adentrarnos en su funcionamiento veremos c&amp;oacute;mo se configura para trabajar con una aplicaci&amp;oacute;n Rails.  La aplicaci&amp;oacute;n que utilizaremos es la conocida aplicaci&amp;oacute;n de &lt;em&gt;blog&lt;/em&gt; que hemos usado en varios episodios anteriores.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/727/original/E280I01.png" width="815" height="452" alt="La aplicaci&#243;n de &lt;em&gt;blog&lt;/em&gt;."/&gt;
&lt;/div&gt;

&lt;p&gt;Si ejecutamos &lt;code&gt;rails c&lt;/code&gt; en el directorio de la aplicaci&amp;oacute;n se activar&amp;aacute; IRB.  Para utilizar Pry s&amp;oacute;lo tenemos que ejecutar &lt;code&gt;pry&lt;/code&gt; pasando el fichero de entorno de Rails.  Cuando lo hagamos tendremos acceso a todos los modelos de nuestra aplicaci&amp;oacute;n igual que con una consola est&amp;aacute;ndar de Rails.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ pry -r ./config/environment
pry(main)&amp;gt; Article.count
=&amp;gt; 3&lt;/pre&gt;

&lt;p&gt;Con esto ya podemos pasar a ver las funcionalidades de Pry.  Si escribimos &lt;code&gt;help&lt;/code&gt; veremos un listado con todas las &amp;oacute;rdenes soportadas pero las dos que usaremos con m&amp;aacute;s frecuencia son &lt;code&gt;cd&lt;/code&gt; y &lt;code&gt;ls&lt;/code&gt;.  La orden &lt;code&gt;cd&lt;/code&gt; cambia el &amp;aacute;mbito actual, por lo que si escribimos &lt;code&gt;cd Article&lt;/code&gt; nos moveremos a la clase &lt;code&gt;Article&lt;/code&gt;.  Podemos comprobar el &amp;aacute;mbito en todo momento escribiendo &lt;code&gt;self&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(main)&amp;gt; cd Article
pry(#&amp;lt;Class:0x1022f60e0&amp;gt;):1&amp;gt; self
=&amp;gt; Article(id: integer, name: string, content: text, created_at: datetime, updated_at: datetime, published_at: datetime)&lt;/pre&gt;

&lt;p&gt;Una vez que estamos dentro de la clase &lt;code&gt;Article&lt;/code&gt; podemos invocar cualquiera de sus m&amp;eacute;todos, como &lt;code&gt;first&lt;/code&gt;, que devuelve el primer art&amp;iacute;culo, igual que si escribi&amp;eacute;semos &lt;code&gt;Article.first&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Class:0x1022f60e0&amp;gt;):1&amp;gt; first
=&amp;gt; #&amp;lt;Article id: 1, name: &amp;quot;What is Music&amp;quot;, content: &amp;quot;Music is an art form in which the medium is sound o...&amp;quot;, created_at: &amp;quot;2011-08-24 20:35:29&amp;quot;, updated_at: &amp;quot;2011-08-24 20:37:22&amp;quot;, published_at: &amp;quot;2011-05-13 23:00:00&amp;quot;&amp;gt;&lt;/pre&gt;

&lt;p&gt;Tambi&amp;eacute;n podemos hacer &lt;code&gt;cd&lt;/code&gt; en cualquier objeto por lo que si hacemos &lt;code&gt;cd first&lt;/code&gt; en el &amp;aacute;mbito &lt;code&gt;Article&lt;/code&gt; cambiaremos al &amp;aacute;mbito de ese art&amp;iacute;culo donde podemos llamar m&amp;eacute;todos de instancia como por ejemplo &lt;code&gt;name&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Class:0x1022f60e0&amp;gt;):1&amp;gt; cd first
pry(#&amp;lt;Article:0x102300c98&amp;gt;):2&amp;gt; name
=&amp;gt; &amp;quot;What is Music&amp;quot;&lt;/pre&gt;

&lt;p&gt;Tambi&amp;eacute;n podemos hacer &lt;code&gt;cd&lt;/code&gt; al atributo &lt;code&gt;name&lt;/code&gt; del art&amp;iacute;culo y trabajar con los m&amp;eacute;todos de dicha cadena.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Article:0x102300c98&amp;gt;):2&amp;gt; cd name
pry(&amp;quot;What is Music&amp;quot;):3&amp;gt; upcase
=&amp;gt; &amp;quot;WHAT IS MUSIC&amp;quot;&lt;/pre&gt;

&lt;p&gt;Pry toma nota del nivel de anidamiento en que nos encontramos.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(&amp;quot;What is Music&amp;quot;):3&amp;gt; nesting
Nesting status:
--
0. main (Pry top level)
1. #&amp;lt;Class:0x1022f60e0&amp;gt;
2. #&amp;lt;Article:0x102300c98&amp;gt;
3. &amp;quot;What is Music&amp;quot;&lt;/pre&gt;

&lt;p&gt;Esta orden devuelve la lista de objetos en los que hemos entrado.  Si escribimos &lt;code&gt;exit&lt;/code&gt; volveremos al objeto anterior, en este caso el primer art&amp;iacute;culo.  Y si volvemos a salir , volveremos a la clase &lt;code&gt;Article&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La siguiente orden m&amp;aacute;s utilizada es &lt;code&gt;ls&lt;/code&gt;, que enumera las variables y sus m&amp;eacute;todos.  Por defecto lista todas las variables del &amp;aacute;mbito actual, por lo que si estamos en &lt;code&gt;Article&lt;/code&gt;, veremos todos los m&amp;eacute;todos disponibles:&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Class:0x1022f60e0&amp;gt;):1&amp;gt; ls
[:_, :_pry_, :inp, :out, :@_create_callbacks, :@_defined_class_methods, :@_save_callbacks, :@_update_callbacks, :@_validate_callbacks, :@arel_engine, :@arel_table, :@attribute_methods_generated, :@cached_attributes, :@column_names, :@columns, :@columns_hash, :@finder_needs_type_condition, :@generated_attribute_methods, :@inheritable_attributes, :@inheritance_column, :@parent_name, :@quoted_primary_key, :@quoted_table_name, :@relation]&lt;/pre&gt;

&lt;p&gt;Algunas &amp;oacute;rdenes de Pry soportan modificadores, que podemos consultar ejecutando la orden con la opci&amp;oacute;n &lt;code&gt;-h&lt;/code&gt;.  Si ejecutamos &lt;code&gt;ls -h&lt;/code&gt; veremos todas las opciones soportadas, incluyendo &lt;code&gt;-m&lt;/code&gt; que podemos usar para mostrar un listado de m&amp;eacute;todos de la clase y &lt;code&gt;-M&lt;/code&gt; que devuelve el listado de los m&amp;eacute;todos de instancia.  Tambi&amp;eacute;n podemos pasarle cualquier objeto o clase para ver sus m&amp;eacute;todos en lugar de los del &amp;aacute;mbito actual.&lt;/p&gt;

&lt;p&gt;Otra orden muy &amp;uacute;til de Pry es &lt;code&gt;show-doc&lt;/code&gt;.  Supongamos que queremos saber c&amp;oacute;mo funciona el m&amp;eacute;todo &lt;code&gt;in_groups_of&lt;/code&gt; de la clase Array.  Podemos hacerlo con &lt;code&gt;show-doc Array#in_groups_of&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Class:0x1022f60e0&amp;gt;):1&amp;gt; show-doc Array#in_groups_of

From: /Users/eifion/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.0.10/lib/active_support/core_ext/array/grouping.rb @ line 19:
Number of lines: 15

signature: in_groups_of(number, fill_with=?)

Splits or iterates over the array in groups of size number,
padding any remaining slots with fill_with unless it is false.

  %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group}
  [&amp;quot;1&amp;quot;, &amp;quot;2&amp;quot;, &amp;quot;3&amp;quot;]
  [&amp;quot;4&amp;quot;, &amp;quot;5&amp;quot;, &amp;quot;6&amp;quot;]
  [&amp;quot;7&amp;quot;, nil, nil]

  %w(1 2 3).in_groups_of(2, &amp;#x27;&amp;amp;nbsp;&amp;#x27;) {|group| p group}
  [&amp;quot;1&amp;quot;, &amp;quot;2&amp;quot;]
  [&amp;quot;3&amp;quot;, &amp;quot;&amp;amp;nbsp;&amp;quot;]

  %w(1 2 3).in_groups_of(2, false) {|group| p group}
  [&amp;quot;1&amp;quot;, &amp;quot;2&amp;quot;]
  [&amp;quot;3&amp;quot;]&lt;/pre&gt;

&lt;p&gt;Tambi&amp;eacute;n podemos invocar &lt;code&gt;show-doc&lt;/code&gt; directamente sobre objetos.  Nuestro &amp;aacute;mbito es la clase &lt;code&gt;Article&lt;/code&gt; por lo que podemos invocar &lt;code&gt;all&lt;/code&gt; para devolver el listado de art&amp;iacute;culos.  Podemos invocar &lt;code&gt;show-doc all.in_groups_of&lt;/code&gt; para recuperar la misma informaci&amp;oacute;n que antes.&lt;/p&gt;

&lt;p&gt;Otra orden &amp;uacute;til es &lt;code&gt;show-method&lt;/code&gt;, que muestra el c&amp;oacute;digo fuente de cualquier m&amp;eacute;todo.  Podemos utilizarlo para ver el c&amp;oacute;digo fuente de &lt;code&gt;in_groups_of&lt;/code&gt; (cabe destacar que Pry ofrece autocompletado de los m&amp;eacute;todos que vamos introduciendo con la tecla de tabulaci&amp;oacute;n). &lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Class:0x104e63de0&amp;gt;):1&amp;gt; show-method all.in_groups_of

From: /Users/eifion/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.0.10/lib/active_support/core_ext/array/grouping.rb @ line 19:
Number of lines: 19

def in_groups_of(number, fill_with = nil)
  if fill_with == false
    collection = self
  else
    # size % number gives how many extra we have;
    # subtracting from number gives how many to add;
    # modulo number ensures we don&amp;#x27;t add group of just fill.
    padding = (number - size % number) % number
    collection = dup.concat([fill_with] * padding)
  end

  if block_given?
    collection.each_slice(number) { |slice| yield(slice) }
  else
    groups = []
    collection.each_slice(number) { |group| groups &amp;lt;&amp;lt; group }
    groups
  end
end&lt;/pre&gt;

&lt;p&gt;Igualmente tenemos la orden &lt;code&gt;edit-method&lt;/code&gt;.  Si lo ejecutamos contra un m&amp;eacute;todo abrir&amp;aacute; el fichero de texto correspondiente en un editor de texto, llev&amp;aacute;ndonos a la l&amp;iacute;nea adecuada.&lt;/p&gt;

&lt;p&gt;Tambi&amp;eacute;n podemos ejecutar &amp;oacute;rdenes de la &lt;em&gt;shell&lt;/em&gt; si vienen precedidas por un punto.  Si ejecutamos &lt;code&gt;.ls&lt;/code&gt; en Pry, &amp;eacute;ste ejecutar&amp;aacute; la orden &lt;code&gt;ls&lt;/code&gt; de la &lt;em&gt;shell&lt;/em&gt; y veremos los ficheros del directorio actual.&lt;/p&gt;

&lt;p&gt;Pry resulta &amp;uacute;til para depurar.  En nuestro modelo &lt;code&gt;Article&lt;/code&gt; tenemos el m&amp;eacute;todo &lt;code&gt;word_count&lt;/code&gt; que deber&amp;iacute;a devolver el n&amp;uacute;mero de palabras que tiene el atributo &lt;code&gt;content&lt;/code&gt; de un art&amp;iacute;culo.  Pero hay un error en dicho c&amp;oacute;digo porque siempre devuelve &lt;code&gt;0&lt;/code&gt; independientemente del contenido que tenga el art&amp;iacute;culo.  Podemos mirar el m&amp;eacute;todo haciendo &lt;code&gt;cd&lt;/code&gt; al primer &lt;code&gt;Article&lt;/code&gt; y luego invocando &lt;code&gt;edit-method word_count&lt;/code&gt;.  El m&amp;eacute;todo tiene el siguiente aspecto:&lt;/p&gt;

&lt;pre class="codeFilePath"&gt;/app/models/article.rb&lt;/pre&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments

  def word_count
    words = content.scan(/\\w+/)
    words.size
  end
end&lt;/pre&gt;

&lt;p&gt;Podemos poner un punto de ruptura en el c&amp;oacute;digo con &lt;code&gt;binding.pry&lt;/code&gt;.  Si lo hacemos justo antes de la l&amp;iacute;nea &lt;code&gt;words.size&lt;/code&gt; y guardamos el archivo, la pr&amp;oacute;xima que ejecutemos &lt;code&gt;word_count&lt;/code&gt; se parar&amp;aacute; en la invocaci&amp;oacute;n de &lt;code&gt;binding.pry&lt;/code&gt; y nos devolver&amp;aacute; a la interfaz de &amp;oacute;rdenes de Pry.&lt;/p&gt;

&lt;pre class="terminal"&gt;&amp;gt; word_count

From: /Users/eifion/blog/app/models/article.rb @ line 7 in Article#word_count:

     2:   attr_accessible :name, :content, :published_at
     3:   has_many :comments
     4: 
     5:   def word_count
     6:     words = content.scan(/\\w+/)
 =&amp;gt;  7:     binding.pry
     8:     words.size
     9:   end
    10: end&lt;/pre&gt;

&lt;p&gt;Tenemos acceso a todas las variables locales del m&amp;eacute;todo, por lo que podemos invocar &lt;code&gt;words&lt;/code&gt; para ver los contenidos del &lt;em&gt;array&lt;/em&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Article:0x1008c3f38&amp;gt;):3&amp;gt; words
=&amp;gt; []&lt;/pre&gt;

&lt;p&gt;Parece que hay algo mal con la expresi&amp;oacute;n regular que recupera el contenido, porque &amp;eacute;ste se encuentra vac&amp;iacute;o.  Examin&amp;aacute;ndola con m&amp;aacute;s detalle veremos que hay dos barras invertidas donde deber&amp;iacute;a haber s&amp;oacute;lo una.  Para corregir esto podemos ejecutar &lt;code&gt;edit-method word_count&lt;/code&gt;, arreglar la expresi&amp;oacute;n regular, quitar la l&amp;iacute;nea &lt;code&gt;binding.pry&lt;/code&gt; y guardar el archivo.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments

  def word_count
    words = content.scan(/\w+/)
    words.size
  end
end&lt;/pre&gt;

&lt;p&gt;Podemos comprobar nuestro arreglo llamado a &lt;code&gt;word_count&lt;/code&gt; de nuevo, y esta vez funciona como ser&amp;iacute;a de esperar.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Article:0x1008c3f38&amp;gt;):3&amp;gt; word_count
=&amp;gt; 55&lt;/pre&gt;

&amp;lt;o&amp;gt;A veces querremos depurar algo en las capas de vista o controlador de la aplicaci&amp;oacute;n y no necesariamente por la consola.  Pry puede ayudarnos, primero tenemos que poner una referencia a Pry en el &lt;code&gt;Gemfile&lt;/code&gt;.&amp;lt;/o&amp;gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;source &amp;#x27;http://rubygems.org&amp;#x27;

gem &amp;#x27;rails&amp;#x27;, &amp;#x27;3.0.10&amp;#x27;
gem &amp;#x27;sqlite3&amp;#x27;
gem &amp;#x27;nifty-generators&amp;#x27;
gem &amp;#x27;pry&amp;#x27;, :group =&amp;gt; :development&lt;/pre&gt;

&lt;p&gt;Luego podemos ejecutar &lt;code&gt;bundle&lt;/code&gt; para instalar las gemas y luego &lt;code&gt;rails s&lt;/code&gt; para arrancar el servidor, y ya podemos ir dejando llamadas a &lt;code&gt;binding.pry&lt;/code&gt; en nuestros controladores para establecer puntos de ruptura.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/articles_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def index
  @articles = Article.all
  binding.pry
end&lt;/pre&gt;

&lt;p&gt;Si abrimos dicha p&amp;aacute;gina con un navegador se quedar&amp;aacute; pegada durante la carga pero en el terminal veremos la interfaz de Pry que ha detenido la ejecuci&amp;oacute;n en el punto de ruptura, donde podemos inspeccionar los valores de las variables locales o de instancia del modelo.  Una vez que hayamos terminado podemos hacer &lt;code&gt;exit&lt;/code&gt; para que la petici&amp;oacute;n finalice.&lt;/p&gt;

&lt;pre class="terminal"&gt;From: /Users/eifion/blog/app/controllers/articles_controller.rb @ line 4 in ArticlesController#index:

     1: class ArticlesController &amp;lt; ApplicationController
     2:   def index
     3:     @articles = Article.all
 =&amp;gt;  4:     binding.pry
     5:   end
     6: 
     7:   def show
     8:     @article = Article.find(params[:id])
     9:   end&lt;/pre&gt;

&lt;p&gt;Con esto terminamos este episodio sobre Pry.  Se trata de una gema muy &amp;uacute;til que hace mucho m&amp;aacute;s que lo que hemos visto hoy.  El  &lt;a href="https://github.com/pry/pry/wiki"&gt;wiki&lt;/a&gt; detalla mucha m&amp;aacute;s informaci&amp;oacute;n e incluye un enlace a un &lt;a href="http://vimeo.com/26391171"&gt;v&amp;iacute;deo&lt;/a&gt; realizado por Joshua Cheek.&lt;/p&gt;</description>
      <pubDate>Sun, 18 Sep 2011 21:15:49 +0000</pubDate>
      <guid>http://es.asciicasts.com/episodes/280-pry-y-rails</guid>
      <link>http://es.asciicasts.com/episodes/280-pry-y-rails</link>
    </item>
    <item>
      <title>El conducto de est&#225;ticos</title>
      <description>&lt;p&gt;El conducto de est&amp;aacute;ticos (&lt;strong&gt;N. del T:&lt;/strong&gt; &lt;em&gt;asset pipeline&lt;/em&gt; en ingl&amp;eacute;s) es una de las funcionalidades m&amp;aacute;s importantes de Rails 3.1, pero tambi&amp;eacute;n es de las m&amp;aacute;s confusas.  En este episodio vamos a tratar de aclarar c&amp;oacute;mo se usa para gestionar los est&amp;aacute;ticos de nuestras aplicaciones Rails.  Los que no est&amp;eacute;n familiarizados con esto pueden empezar por la &lt;a href="http://guides.rubyonrails.org/asset_pipeline.html"&gt;Gu&amp;iacute;a Rails sobre el conducto de est&amp;aacute;ticos&lt;/a&gt; porque cubre muchas de sus funcionalidades.&lt;/p&gt;

&lt;p&gt;Los que ya hayan escrito una aplicaci&amp;oacute;n Rails 3.1 sabr&amp;aacute;n que si visitamos  &lt;code&gt;&lt;a href="http://localhost:3000/assets/application.js"&gt;http://localhost:3000/assets/application.js&lt;/a&gt;&lt;/code&gt; veremos un archivo con todo el JavaScript que utiliza nuestra aplicaci&amp;oacute;n.  Pero, &amp;iquest;c&amp;oacute;mo funciona esto?&lt;/p&gt;

&lt;p&gt;El fichero &lt;code&gt;application.js&lt;/code&gt; no tiene nada de especial; de hecho cualquier fichero que se ponga en el directorio &lt;code&gt;/app/assets/javascripts&lt;/code&gt; ser&amp;aacute; accesible igualmente.  Por ejemplo si en dicho directorio creamos un fichero llamado &lt;code&gt;greeting.txt&lt;/code&gt; podemos verlo con el navegador cargando la URL  &lt;a href="http://localhost:3000/assets/greeting.txt"&gt;&lt;code&gt;http://localhost:3000/assets/greeting.txt&lt;/code&gt;&lt;/a&gt;. N&amp;oacute;tese que aunque el fichero se encuentra en el directorio  &lt;code&gt;/app/assets/javascripts&lt;/code&gt; la URL que usamos para acceder a &amp;eacute;l es &lt;code&gt;/assets/greeting.txt&lt;/code&gt;.  Esto se aplica para cualquier subdirectorio de &lt;code&gt;/app/assets&lt;/code&gt; en el que pongamos el archivo, podemos incluso crear un nuevo directorio y ponerlo ah&amp;iacute;, que el fichero seguir&amp;aacute; estando accesible en la misma URL (aunque si hacemos esto tendremos que reiniciar el servidor).&lt;/p&gt;

&lt;p&gt;El directorio &lt;code&gt;/app/assets&lt;/code&gt; no es el &amp;uacute;nico sitio donde podemos a&amp;ntilde;adir este tipo de est&amp;aacute;ticos.  Si creamos un directorio en &lt;code&gt;/lib/assets&lt;/code&gt; cualquier fichero que pongamos ah&amp;iacute; podr&amp;aacute; ser accedido igual que si hubiese sido puesto en &lt;code&gt;/app/assets&lt;/code&gt;, y lo mismo para todos los ficheros que cuelguen de &lt;code&gt;/vendor/assets&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si tenemos archivos est&amp;aacute;ticos que no son realmente espec&amp;iacute;ficos de la aplicaci&amp;oacute;n nos puede venir bien ponerlos o bien en &lt;code&gt;/lib&lt;/code&gt; o en &lt;code&gt;/vendor&lt;/code&gt;.  Por ejemplo si usamos un &lt;em&gt;plugin&lt;/em&gt; de jQuery el directorio &lt;code&gt;/vendor/assets&lt;/code&gt; es un buen sitio para poner los ficheros JavaScript porque es otra persona quien los mantiene.  Igualmente podemos poner en &lt;code&gt;/lib&lt;/code&gt; aquellos est&amp;aacute;ticos que mantenemos nosotros pero que no son espec&amp;iacute;ficos de la aplicaci&amp;oacute;n.&lt;/p&gt;

&lt;p&gt;Simplificando, el conducto de est&amp;aacute;ticos no es m&amp;aacute;s que una lista de rutas de carga.  Podemos ver dicho listado consultado en la consola &lt;code&gt;Rails.application.config.assets.paths&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="terminal"&gt;&amp;gt; y Rails.application.config.assets.paths
--- 
- /Users/eifion/store/app/assets/images
- /Users/eifion/store/app/assets/javascripts
- /Users/eifion/store/app/assets/stylesheets
- /Users/eifion/store/lib/assets/greeting.txt
- /Users/eifion/store/vendor/assets/stylesheets
- /Users/eifion/.rvm/gems/ruby-1.9.2-p180@railspre/gems/jquery-rails-1.0.13/vendor/assets/javascripts&lt;/pre&gt;

&lt;p&gt;La salida muestra todos los directorios debajo de &lt;code&gt;app/assets&lt;/code&gt;, de &lt;code&gt;/lib/assets&lt;/code&gt; y de &lt;code&gt;/vendor/assets&lt;/code&gt;.  Al final aparece un directorio interesante que viene de la gema  &lt;code&gt;jquery-rails&lt;/code&gt; que hemos incluido en nuestra aplicaci&amp;oacute;n.  Podemos ver sus contenidos con la orden &lt;code&gt;bundle open&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ bundle open jquery-rails&lt;/pre&gt;

&lt;p&gt;Con esto abriremos la gema con el editor de texto definido por las variables de entorno &lt;code&gt;BUNDLE_EDITOR&lt;/code&gt; o &lt;code&gt;EDITOR&lt;/code&gt;.  Si examinamos los ficheros de la gema veremos un directorio llamado &lt;code&gt;vendor/asset/javascripts&lt;/code&gt; y que contiene varios ficheros de jQuery que podemos cargar a trav&amp;eacute;s del conducto de est&amp;aacute;ticos.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/723/original/E279I01.png" width="801" height="377" alt="Ficheros y estructura de carpetas de la gema jquery-rails."/&gt;
&lt;/div&gt;

&lt;p&gt;Tal y como es de esperar, podemos acceder a cualquiera de estos archivos en la ruta &lt;code&gt;assets&lt;/code&gt; en el navegador, porque todos estos directorios se encuentran en la ruta de carga del conducto de est&amp;aacute;ticos.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/724/original/E279I02.png" width="801" height="437" alt="El fichero jquery.js file est&#225; accesible en la URL /assets."/&gt;
&lt;/div&gt;

&lt;p&gt;Lo m&amp;aacute;s interesante de esto es que las gemas de Ruby ya no sirven s&amp;oacute;lo para gestionar c&amp;oacute;digo Ruby, tambi&amp;eacute;n podemos usarlas para gestionar JavaScript y otro est&amp;aacute;ticos.  Probablemente veamos en un futuro m&amp;aacute;s librer&amp;iacute;as de JavaScript distribuidas como gemas de Ruby de forma que puedan aprovecharse de la gesti&amp;oacute;n de dependencias de Bundler.&lt;/p&gt;

&lt;h3&gt;Gesti&amp;oacute;n de est&amp;aacute;ticos con Sprockets&lt;/h3&gt;

&lt;p&gt;Volvamos al fichero &lt;code&gt;application.js&lt;/code&gt; de nuestra aplicaci&amp;oacute;n, y ech&amp;eacute;mosle un vistazo.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/javascripts/application.js&lt;/p&gt;
&lt;pre class="javascript"&gt;// This is a manifest file that&amp;#x27;ll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they&amp;#x27;ll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It&amp;#x27;s not advisable to add code directly here, but if you do, it&amp;#x27;ll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require_tree .&lt;/pre&gt;

&lt;p&gt;El fichero s&amp;oacute;lo contiene comentarios, pero son importantes.  Este tipo de archivo se conoce como &lt;em&gt;manifiesto&lt;/em&gt; y lo gestiona  &lt;a href="http://getsprockets.org/"&gt;Sprockets&lt;/a&gt; internamente.  Cuando llega una petici&amp;oacute;n para este archivo, Sprockets mira el manifiesto y recopila todos los ficheros mencionados y pone sus contenidos antes del c&amp;oacute;digo que aparezca en este archivo.&lt;/p&gt;

&lt;p&gt;Aqu&amp;iacute; tambi&amp;eacute;n funcionan las rutas de carga.  En este fichero tenemos &lt;code&gt;require jquery&lt;/code&gt; (la extensi&amp;oacute;n &lt;code&gt;.js&lt;/code&gt; es opcional).  Sprockets buscar&amp;aacute; en los directorios mencionados en la ruta de carga en busca de este archivo y, en este caso, lo cargar&amp;aacute; del directorio &lt;code&gt;vendor/asset/javascripts&lt;/code&gt;de la gema.&lt;/p&gt;

&lt;p&gt;Se puede poner aqu&amp;iacute; cualquier fichero JavaScript que se encuentre en la ruta de carga.  As&amp;iacute;, si a&amp;ntilde;adimos &lt;code&gt;require jquery-ui&lt;/code&gt; a este archivo, se incluir&amp;aacute; el c&amp;oacute;digo &lt;code&gt;jquery-ui&lt;/code&gt; de la gema.  Esto tambi&amp;eacute;n se aplica a los ficheros de CoffeeScript, si incluimos &lt;code&gt;require home&lt;/code&gt; se analizar&amp;aacute; e incluir&amp;aacute; el fichero &lt;code&gt;/app/assets/javascripts/home.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Sin embargo no hace falta incluir dicho fichero &lt;code&gt;home&lt;/code&gt;  porque al final de este archivo tenemos &lt;code&gt;require_tree .&lt;/code&gt;, y el punto aqu&amp;iacute; quiere decir el directorio actual.  Todos los ficheros JavaScript o CoffeScript que haya en este directorio y sus hijos ser&amp;aacute;n autom&amp;aacute;ticamente incluidos.&lt;/p&gt;

&lt;p&gt;Podemos excluir algunos archivos si queremos.  Supongamos que tenemos unas p&amp;aacute;ginas de administraci&amp;oacute;n y s&amp;oacute;lo queremos incluir su JavaScript cuando estamos viendo una de estas p&amp;aacute;gias.  Por defecto estos ficheros ser&amp;iacute;an incluidos para todas las p&amp;aacute;ginas de nuestro sitio.&lt;/p&gt;

&lt;p&gt;Si queremos ver qu&amp;eacute; ficheros se est&amp;aacute;n incluyendo podemos a&amp;ntilde;adir el par&amp;aacute;metro &lt;code&gt;debug_assets=1&lt;/code&gt; a la URL, con lo que impediremos que se combinen los archivos JavaScript y si vemos el c&amp;oacute;digo fuente de la p&amp;aacute;gina veremos todos los archivos que Sprockets habr&amp;iacute;a incluido, y veremos que tambi&amp;eacute;n aparecen los del directorio &lt;code&gt;admin&lt;/code&gt;.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/725/original/E279I03.png" width="789" height="322" alt="Los ficheros JavaScript no se combinan si a&#241;adimos el par&#225;metro debug_asssets en la URL."/&gt;
&lt;/div&gt;

&lt;p&gt;Esto lo podemos soslayar de un par de formas.  Por un lado podr&amp;iacute;amos utilizar &lt;code&gt;require_directory&lt;/code&gt; en lugar de &lt;code&gt;require_tree&lt;/code&gt; y esto incorporar&amp;iacute;a los ficheros del directorio actual, y no los del subdirectorio, y por otra parte si queremos tener m&amp;aacute;s control podr&amp;iacute;amos hacer &lt;code&gt;require&lt;/code&gt; de forma separada en lugar de incluir todo el directorio.  Alternativamente podr&amp;iacute;amos mover los ficheros JavaScript a un directorio &lt;code&gt;public&lt;/code&gt; y luego usar &lt;code&gt;require_tree ./public&lt;/code&gt; para incluir s&amp;oacute;lo dichos archivos.&lt;/p&gt;

&lt;p&gt;Cabe preguntarse qu&amp;eacute; comandos hay disponibles en el manifiesto de Sprocket, por desgracia no hay una fuente definitiva de documentaci&amp;oacute;n pero en el fichero  &lt;a href="https://github.com/sstephenson/sprockets/blob/master/lib/sprockets/directive_processor.rb"&gt;&lt;code&gt;directive_processor.rb&lt;/code&gt;&lt;/a&gt; existen comentarios que explican c&amp;oacute;mo funciona, as&amp;iacute; como las distintas &amp;oacute;rdenes que se le pueden pasar.&lt;/p&gt;

&lt;h3&gt;Preprocesado&lt;/h3&gt;

&lt;p&gt;El conducto de est&amp;aacute;ticos tambi&amp;eacute;n puede preprocesar.  Para ver c&amp;oacute;mo funciona esto crearemos un fichero llamado &lt;code&gt;greeting.txt&lt;/code&gt; en el nuevo directorio &lt;code&gt;/app/assets/anything&lt;/code&gt;.  Podemos a&amp;ntilde;adir otra extensi&amp;oacute;n al nombre de archivo y especificar un procesador, por ejemplo &lt;code&gt;.erb&lt;/code&gt;.  Si ahora le a&amp;ntilde;adimos c&amp;oacute;digo ERB a este archivo se evaluar&amp;aacute; correctamente.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/app/assets/anything/greeting.txt.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;hello world &amp;lt;%= 1 + 1 %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Si cargamos el fichero en un navegador veremos que el c&amp;oacute;digo ERB se ha ejecutado correctamente.  N&amp;oacute;tese que no incluimos la URL no incluye la extensi&amp;oacute;n del preprocesador.&lt;/p&gt;


&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/726/original/E279I04.png" width="801" height="280" alt="Se preprocesa el c&#243;digo erb antes de enviar el fichero al navegador."/&gt;
&lt;/div&gt;

&lt;p&gt;As&amp;iacute; es como b&amp;aacute;sicamente funcionan SASS y CoffeeScript.  Cuando un fichero tiene la extensi&amp;oacute;n &lt;code&gt;.sc&lt;/code&gt; &amp;eacute;sta indica que hay que preprocesarlo con SASS.  Podemos encadenar este tipo de extensi&amp;oacute;n y crear un fichero con la extensi&amp;oacute;n, por ejemplo &lt;code&gt;.scss.erb&lt;/code&gt;, con lo que el fichero primero pasar&amp;iacute;a por ERB y luego por SASS.&lt;/p&gt;

&lt;p&gt;El preprocesador es muy configurable.  Podemos a&amp;ntilde;adir nuestros propios procesador o intercambiar los ya existentes, todo esto se controla con la 
&lt;a href="https://github.com/rtomayko/tilt/"&gt;gema Tilt&lt;/a&gt;, en cuya documentaci&amp;oacute;n se puede encontrar toda la informaci&amp;oacute;n necesaria.&lt;/p&gt;

&lt;h3&gt;Diferencias en modo de producci&amp;oacute;n&lt;/h3&gt;

&lt;p&gt;Con esto terminamos esta peque&amp;ntilde;a gu&amp;iacute;a sobre la funcionalidad del conducto de est&amp;aacute;tico, pero hay algunas diferencias de funcionamiento en producci&amp;oacute;.  Primero, arrancaremos el servidor en modo de producci&amp;oacute;n.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails s -e production&lt;/pre&gt;

&lt;p&gt;Si visitamos la p&amp;aacute;gina principal de nuestra aplicaci&amp;oacute;n y vemos el c&amp;oacute;digo fuente compobaremos que los est&amp;aacute;ticos se sirven de forma diferente.&lt;/p&gt;

&lt;pre class="terminal"&gt;&amp;lt;link href=&amp;quot;/assets/application-412fe22651f4486c51e54176003a9f57.css&amp;quot; media=&amp;quot;screen&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;
  &amp;lt;script src=&amp;quot;/assets/application-3e3a5167191afa70c7b72440eee7dd40.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;Por motivos de cach&amp;eacute;, ahora los nombres de archivo aparecen con un gui&amp;oacute;n.  Esto da  mejor resultado que el viejo m&amp;eacute;todo que usa Rails 3.0 de a&amp;ntilde;adir una cadena porque cambia realmente el nombre del archivo.  Tambi&amp;eacute;n si vemos el contenido del fichero veremos que el JavaScript ha sido minimizado, lo que ahorra ancho de banda.&lt;/p&gt;

&lt;p&gt;Estos est&amp;aacute;ticos se cachean autom&amp;aacute;ticamente y son servidos por el &lt;em&gt;middleware&lt;/em&gt; Rack Cache, lo que es bastante r&amp;aacute;pido.  Si queremos que sea el propio servidor web quien sirva estos est&amp;aacute;ticos podemos precompilarlos lanzando&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rake assets:precompile&lt;/pre&gt;

&lt;p&gt;Con esto se precompilar&amp;aacute;n los est&amp;aacute;ticos en el directorio &lt;code&gt;/public&lt;/code&gt; de forma que ser&amp;aacute;n accesibles desde el servidor web.&lt;/p&gt;

&lt;p&gt;Con esto concluimos este episodio sobre el conducto de est&amp;aacute;ticos.  No olvideis visitar la &lt;a href="http://ryanbigg.com/guides/asset_pipeline.html"&gt;Gu&amp;iacute;a de Rails&lt;/a&gt; que contiene m&amp;aacute;s informaci&amp;oacute;n.&lt;/p&gt;
</description>
      <pubDate>Sat, 10 Sep 2011 20:58:10 +0000</pubDate>
      <guid>http://es.asciicasts.com/episodes/279-el-conducto-de-estaticos</guid>
      <link>http://es.asciicasts.com/episodes/279-el-conducto-de-estaticos</link>
    </item>
    <item>
      <title>B&#250;squedas con Sunspot</title>
      <description>&lt;p&gt;Con &lt;a href="http://outoftime.github.com/sunspot"&gt;Sunspot&lt;/a&gt; podemos a&amp;ntilde;adir b&amp;uacute;squeda de texto completo en nuestras aplicaciones Ruby. Utiliza &lt;a href="http://lucene.apache.org/solr/"&gt;Solr&lt;/a&gt; en segundo plano y tiene muchas caracter&amp;iacute;sticas interesantes.  En este episodio veremos c&amp;oacute;mo usar Sunspot para a&amp;ntilde;adir este tipo de b&amp;uacute;squedas en una aplicaci&amp;oacute;n Rails, utilizando la sencilla aplicaci&amp;oacute;n de &lt;em&gt;blog&lt;/em&gt; que hemos visto en los episodios anteriores.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/718/original/E278I01.png" width="800" height="432" alt="Nuestro blog."/&gt;
&lt;/div&gt;

&lt;p&gt;En esta aplicaci&amp;oacute;n hay una p&amp;aacute;gina que muestra varios art&amp;iacute;culos y en la que queremos implementar la posibilidad de buscar texto en ellos.  Esto se puede complicar considerablemente si utilizamos SQL para hacerlo, as&amp;iacute; que el mejor enfoque suele ser utilizar un motor de b&amp;uacute;squeda de texto completo como Sunspot.&lt;/p&gt;

&lt;h3&gt;Instalaci&amp;oacute;n de Sunspot&lt;/h3&gt;

&lt;p&gt;Sunspot se instala como una gema de la forma habitual, a&amp;ntilde;adi&amp;eacute;ndolo al &lt;code&gt;Gemfile&lt;/code&gt; y ejecutando &lt;code&gt;bundle&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;source &amp;#x27;http://rubygems.org&amp;#x27;

gem &amp;#x27;rails&amp;#x27;, &amp;#x27;3.0.9&amp;#x27;
gem &amp;#x27;sqlite3&amp;#x27;
gem &amp;#x27;nifty-generators&amp;#x27;
gem &amp;#x27;sunspot_rails&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Una vez que hayamos instalado la gema y sus dependencias tenemos que generar el fichero de configuraci&amp;oacute;n de Sunspot, lo que podemos hacer ejecutando&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g sunspot_rails:install&lt;/pre&gt;

&lt;p&gt;Esta orden crea un fichero YAML en &lt;code&gt;/config/sunspot.yml&lt;/code&gt;. No tenemos que hacer por el momento ning&amp;uacute;n cambio en los valores configurados por defecto.&lt;/p&gt;

&lt;p&gt;No tenemos que instalar Solr por separado porque viene incluido en la propia gema por lo que funciona tal cual, lo que hace que su uso en tiempo de desarrollo sea bastante m&amp;aacute;s c&amp;oacute;modo .  Para arrancar Solr tenemos que ejecutar&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rake sunspot:solr:start&lt;/pre&gt;

&lt;p&gt;Los que est&amp;eacute;n ejecutando OS X Lion y no hayan instalado el entorno de ejecuci&amp;oacute;n de Java podr&amp;aacute;n hacerlo al lanzar la orden.  La orden tambi&amp;eacute;n crear&amp;aacute; m&amp;aacute;s archivos de configuraci&amp;oacute;n avanzada, que no veremos por el momento y cuyo funcionamiento podemos consultar en  &lt;a href="http://outoftime.github.com/sunspot/docs/index.html"&gt;la documentaci&amp;oacute;n&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Uso de Sunspot&lt;/h3&gt;

&lt;p&gt;Una vez que hemos instalado Sunspot podemos utilizarlo sobre nuestro modelo &lt;code&gt;Article&lt;/code&gt;.  Para a&amp;ntilde;adir la b&amp;uacute;squeda de texto completo utilizaremos el m&amp;eacute;todo &lt;code&gt;searchable&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :content
  end
end&lt;/pre&gt;

&lt;p&gt;Este m&amp;eacute;todo recibe un bloque en cuyo interior definiremos los atributos sobre los que queremos realizar las b&amp;uacute;squedas, para que Sunspot pueda saber qu&amp;eacute; datos tiene que indexar.  Podemos usar el m&amp;eacute;todo &lt;code&gt;text&lt;/code&gt; para definir los atributos sobre los que se lanzar&amp;aacute;n b&amp;uacute;squedas de texto completo.  En el caso de nuestros art&amp;iacute;culos lo haremos contra los campos &lt;code&gt;name&lt;/code&gt; y &lt;code&gt;content&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Sunspot indexar&amp;aacute; autom&amp;aacute;ticamente los nuevos registros, pero no los ya existentes.  Podemos decirle que vuelva a generar todo el &amp;iacute;ndice con&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rake sunspot:reindex&lt;/pre&gt;

&lt;p&gt;Una vez que todos los art&amp;iacute;culos se encuentren en nuestra base de datos Solr ya podemos a&amp;ntilde;adir un campo de b&amp;uacute;squeda en la parte superior de la p&amp;aacute;gina.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/articles/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;% title &amp;quot;Articles&amp;quot; %&amp;gt;

&amp;lt;%= form_tag articles_path, :method =&amp;gt; :get do %&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;%= text_field_tag :search, params[:search] %&amp;gt;
    &amp;lt;%= submit_tag &amp;quot;Search&amp;quot;, :name =&amp;gt; nil %&amp;gt;
&amp;lt;% end %&amp;gt;
&amp;lt;!-- rest of view omitted --&amp;gt;&lt;/pre&gt;

&lt;p&gt;Este formulario se env&amp;iacute;a a la acci&amp;oacute;n &lt;code&gt;index&lt;/code&gt; utilizando GET por lo que los par&amp;aacute;metros aparecer&amp;aacute;n en la URL.  Para realizar una b&amp;uacute;squeda con Sunspot invocaremos a &lt;code&gt;search&lt;/code&gt; sobre el modeloy le pasaremos un bloque, en el cual podemos invocar a varios m&amp;eacute;todos para gestionar b&amp;uacute;squedas m&amp;aacute;s complejas.  Empezaremos con el m&amp;eacute;todo &lt;code&gt;fulltext&lt;/code&gt; y le pasaremos los par&amp;aacute;metros recibidos por el formulario.  Por &amp;uacute;ltimo le asignaremos los resultados a la variable &lt;code&gt;@search&lt;/code&gt; a la cual podemos invocar el m&amp;eacute;todo &lt;code&gt;results&lt;/code&gt; para recuperar los art&amp;iacute;culos.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/articles_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def index
  @search = Article.search do
    fulltext params[:search]
  end
  @articles = @search.results
end&lt;/pre&gt;

&lt;p&gt;Ya podemos probar esto recargando la p&amp;aacute;gina de art&amp;iacute;culos y buscando una palabra cualquiera.  Cuando lo hagamos veremos el listado de los art&amp;iacute;culos que la contienen.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/719/original/E278I02.png" width="800" height="565" alt="El listado de art&#237;culos filtrados."/&gt;
&lt;/div&gt;

&lt;p&gt;La b&amp;uacute;squeda devuelve un listado de los art&amp;iacute;culos que contienen el t&amp;eacute;rmino de b&amp;uacute;squeda, ya se encuentre en las columnas &lt;code&gt;nombre&lt;/code&gt; o en su &lt;code&gt;content&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por supuesto, en el bloque &lt;code&gt;searchable&lt;/code&gt; podemos hacer muchas m&amp;aacute;s cosas.  Podemos utilizar &lt;code&gt;boost&lt;/code&gt; para ponderar los resultados, de forma que si hay una correspondencia en el t&amp;iacute;tulo del art&amp;iacute;culo tenga m&amp;aacute;s peso que si se encuentra en el contenido.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :boost =&amp;gt; 5
    text :content
  end
end&lt;/pre&gt;

&lt;p&gt;Esto es muy importante si queremos ordenar los resultados por relevancia.  En este caso los art&amp;iacute;culos cuyos t&amp;iacute;tulo contengan el t&amp;eacute;rmino de b&amp;uacute;squeda aparecer&amp;aacute;n antes en los resultados.&lt;/p&gt;

&lt;p&gt;Los atributos que aparezcan en el bloque &lt;code&gt;searchable&lt;/code&gt; no tienen por qu&amp;eacute; ser columnas reales de la base de datos: podemos utilizar cualquier m&amp;eacute;todo definido en el modelo.  Por ejemplo podemos crear una columna &lt;code&gt;publish_month&lt;/code&gt; que devuelva una cadena conteniendo el nombre del mes y el a&amp;ntilde;o de publicaci&amp;oacute;n del art&amp;iacute;culo, y luego buscaremos sobre este atributo como si estuviese almacenado en la base de datos.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :boost =&amp;gt; 5
    text :content, :publish_month
  end
  
  def publish_month
    published_at.strftime(&amp;quot;%B %Y&amp;quot;)
  end
  
end&lt;/pre&gt;

&lt;p&gt;Antes de poder hacer b&amp;uacute;squedas sobre esta nueva columna tenemos que volver a indexar los registros ejecutando &lt;code&gt;rake sunspot:reindex&lt;/code&gt;, y una vez que lo hagamos podemos buscar los art&amp;iacute;culos por el mes de su publicaci&amp;oacute;n.&lt;/p&gt;


&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/720/original/E278I03.png" width="800" height="420" alt="Los art&#237;culos filtrados por mes de publicaci&#243;n"&gt;
&lt;/div&gt;

&lt;p&gt;Como alternativa a la creaci&amp;oacute;n de un m&amp;eacute;todo podemos pasar un bloque y realizar la b&amp;uacute;squeda contra los resultados de dicho bloque.  Por ejemplo, un art&amp;iacute;culo tiene muchos comentarios por lo que queremos tener la posibilidad de buscar en dichos comentarios.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :boost =&amp;gt; 5
    text :content, :publish_month
    text :comments do
      comments.map(&amp;amp;:content)
    end
  end
  
  def publish_month
    published_at.strftime(&amp;quot;%B %Y&amp;quot;)
  end
  
end&lt;/pre&gt;

&lt;p&gt;El contenido dentro del bloque es una instancia de &lt;code&gt;Article&lt;/code&gt; por lo que en su interior podemos recuperar los comentarios y mapear el contenido de cada comentario.  Aunque esto devuelve un &lt;em&gt;array&lt;/em&gt; Sunspot lo gestionar&amp;aacute; e indexar&amp;aacute; todos los comentarios de forma que luego se pueda buscar sobre ellos.&lt;/p&gt;

&lt;h3&gt;B&amp;uacute;squeda contra atributos&lt;/h3&gt;

&lt;p&gt;&amp;iquest;Y si queremos a&amp;ntilde;adir alg&amp;uacute;n tipo de b&amp;uacute;squeda que vaya m&amp;aacute;s all&amp;aacute; de la b&amp;uacute;squeda de texto completo, tal vez buscar alg&amp;uacute;n atributo espec&amp;iacute;fico?  Para esto le podemos decir el tipo del atributo que queremos buscar: cadena, entero, flotante o incluso una fecha.  Para que el atributo &lt;code&gt;published_at&lt;/code&gt; sea indexable podemos utilizar el m&amp;eacute;todo &lt;code&gt;time&lt;/code&gt;.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :boost =&amp;gt; 5
    text :content, :publish_month
    text :comments do
      comments.map(&amp;amp;:content)
    end
    time :published_at
  end
  
  def publish_month
    published_at.strftime(&amp;quot;%B %Y&amp;quot;)
  end
  
end&lt;/pre&gt;

&lt;p&gt;Podemos utilizar esto en &lt;code&gt;ArticlesController&lt;/code&gt; para restringir las b&amp;uacute;squedas s&amp;oacute;lo a aquellos art&amp;iacute;culos cuya fecha &lt;code&gt;published_at&lt;/code&gt; sea anterior a la hora actual, usando el m&amp;eacute;todo &lt;code&gt;with&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/articles_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def index
  @search = Article.search do
    fulltext params[:search]
    with(:published_at).less_than(Time.zone.now)
  end
  @articles = @search.results
end&lt;/pre&gt;

&lt;p&gt;Con esto la b&amp;uacute;squeda ya no devolver&amp;aacute; art&amp;iacute;culos que no hayan sido publicados todav&amp;iacute;a.  Los atributos que se pueden pasar est&amp;aacute;n bien documentados en  &lt;a href="https://github.com/outoftime/sunspot/wiki/Scoping-by-attribute-fields"&gt;el wiki de Sunspot&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;B&amp;uacute;squeda facetada&lt;/h3&gt;

&lt;p&gt;La b&amp;uacute;squeda facetada permite filtrar los resultados de b&amp;uacute;squeda bas&amp;aacute;ndonos en ciertos atributos tales como el mes en que se public&amp;oacute; el art&amp;iacute;culo.  Supongamos que queremos un listado de los meses en los que hay art&amp;iacute;culos publicados.  Cuando hagamos clic en uno de estos enlaces se filtrar&amp;aacute; el listado de art&amp;iacute;culos de forma que s&amp;oacute;lo aparecer&amp;aacute;n los que hayan sido publicados en dicho mes.&lt;/p&gt;

&lt;p&gt;Para esto primero tenemos que a&amp;ntilde;adir un atributo &lt;code&gt;string&lt;/code&gt; al bloque &lt;code&gt;searchable&lt;/code&gt; de nuestro m&amp;eacute;todo &lt;code&gt;publish_month&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :boost =&amp;gt; 5
    text :content, :publish_month
    text :comments do
      comments.map(&amp;amp;:content)
    end
    time :published_at
    string :publish_month
  end
  
  def publish_month
    published_at.strftime(&amp;quot;%B %Y&amp;quot;)
  end
  
end&lt;/pre&gt;

&lt;p&gt;Podemos convertir esto en una faceta llamando a &lt;code&gt;facet&lt;/code&gt; en el bloque &lt;code&gt;search&lt;/code&gt; de &lt;code&gt;ArticlesController&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/articles_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def index
  @search = Article.search do
    fulltext params[:search]
    with(:published_at).less_than(Time.zone.now)
    facet(:publish_month)
  end
  @articles = @search.results
end&lt;/pre&gt;

&lt;p&gt;Ya podemos listar dichas facetas en la p&amp;aacute;gina &lt;code&gt;index&lt;/code&gt; con el siguiente c&amp;oacute;digo:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/articles/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;div id=&amp;quot;facets&amp;quot;&amp;gt;
  &amp;lt;h3&amp;gt;Published&amp;lt;/h3&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;% for row in @search.facet(:publish_month).rows %&amp;gt;
      &amp;lt;li&amp;gt;
        &amp;lt;% if params[:month].blank? %&amp;gt;
          &amp;lt;%= link_to row.value, :month =&amp;gt; row.value %&amp;gt; (&amp;lt;%= row.count %&amp;gt;)
        &amp;lt;% else %&amp;gt;
          &amp;lt;strong&amp;gt;&amp;lt;%= row.value %&amp;gt;&amp;lt;/strong&amp;gt; (&amp;lt;%= link_to &amp;quot;remove&amp;quot;, :month =&amp;gt; nil %&amp;gt;)
        &amp;lt;% end %&amp;gt;
      &amp;lt;/li&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;

&lt;p&gt;En este c&amp;oacute;digo iteramos sobre los elementos de la faceta &lt;code&gt;publish_month&lt;/code&gt; y los mostramos.  Si invocamos a &lt;code&gt;.facet&lt;/code&gt; en nuestro objeto &lt;code&gt;@search&lt;/code&gt; y le pasamos el atributo por el que queremos filtrar la faceta (en este caso &lt;code&gt;:publish_month&lt;/code&gt;) y luego invocamos a &lt;code&gt;.rows&lt;/code&gt; devolver&amp;aacute; todas las opciones de facetas para dicho atributo.&lt;/p&gt;

&lt;p&gt;Si invocamos &lt;code&gt;row.value&lt;/code&gt; devuelve el valor de dicho atributo, esto es  &amp;ldquo;January 2011&amp;rdquo;. Tambi&amp;eacute;n podemos invocar  &lt;code&gt;row.count&lt;/code&gt; para devulver el n&amp;uacute;mero de art&amp;iacute;culos que coincidan con dicho valor.  Si hay un par&amp;aacute;metro &lt;code&gt;month&lt;/code&gt; en la cadena de b&amp;uacute;squeda mostraremos el valor as&amp;iacute; como un enlace  &amp;ldquo;remove&amp;rdquo; que quitar&amp;aacute; dicho par&amp;aacute;metros, con lo que tenemos la funcionalidad de que podemos especificar una faceta determinada y pasarla mediante el par&amp;aacute;metro &lt;code&gt;month&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si ahora recargamos la p&amp;aacute;gina (tras volver a generar los &amp;iacute;ndices) veremos un listado de facetas en un panel, cada una de las cuales muestra un mes y el n&amp;uacute;mero de art&amp;iacute;culos publicados en dicho mes.  Si escogemos un mes veremos que aparece como par&amp;aacute;metro &lt;code&gt;month&lt;/code&gt; en la URL pero los art&amp;iacute;culos no se filtran.  Para corregirlo, tenemos que a&amp;ntilde;adir otra llamada a &lt;code&gt;with&lt;/code&gt; en el controlador para que filtre por el mes si aparece como par&amp;aacute;metro &lt;code&gt;month&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/articles_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def index
  @search = Article.search do
    fulltext params[:search]
    with(:published_at).less_than(Time.zone.now)
    facet(:publish_month)
    with(:publish_month, params[:month]) &amp;crarr; 
      if params[:month].present?
  end
  @articles = @search.results
end&lt;/pre&gt;

&lt;p&gt;Cuando ahora seleccionemos un mes el listado se filtrar&amp;aacute; correctamente y s&amp;oacute;lo aparecer&amp;aacute;n los art&amp;iacute;culos publicados en dicho mes.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/721/original/E278I04.png" width="800" height="439" alt="Art&#237;culos filtrados usando el mes como faceta."/&gt;
&lt;/div&gt;

&lt;p&gt;Si se pulsa en el enlace  &amp;ldquo;remove&amp;rdquo; volveremos al listado completo.  Esto funciona tambi&amp;eacute;n en conjunci&amp;oacute;n con los resultados de b&amp;uacute;squedaas&amp;iacute; que si buscamos una cadena de texto el listado del panel mostrar&amp;aacute; los meses con art&amp;iacute;culos en los que aparezca dicha cadena.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/722/original/E278I05.png" width="800" height="581" alt="En la barra lateral aparecen los meses de publicaci&#243;n de los art&#237;culos buscados."/&gt;
&lt;/div&gt;

&lt;p&gt;Las facetas son un gran complemento a las b&amp;uacute;squedas de texto completo.&lt;/p&gt;

&lt;p&gt;Con esto finalizamos este episodio.  Sunspot permite a&amp;ntilde;adir b&amp;uacute;squeda de texto completo en nuestras aplicaciones Rails y tiene muchas funcionalidades extra que no hemos visto hoy.  Para m&amp;aacute;s informaci&amp;oacute;n, se puede consultar  &lt;a href="https://github.com/outoftime/sunspot/wiki/"&gt;el wiki de Sunspot&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Sat, 10 Sep 2011 20:48:49 +0000</pubDate>
      <guid>http://es.asciicasts.com/episodes/278-busquedas-con-sunspot</guid>
      <link>http://es.asciicasts.com/episodes/278-busquedas-con-sunspot</link>
    </item>
    <item>
      <title>Engines montables</title>
      <description>&lt;p&gt;Gracias al trabajo de los participantes en el Rails 3.1 Hackfest ya se encuentra disponible la quinta versi&amp;oacute;n candidata de Rails 3.1, que incorpora  correcciones importantes en el montaje de &lt;em&gt;engines&lt;/em&gt; que permiten montar una aplicaci&amp;oacute;n Rails dentro de otra, lo que estudiaremos en este episodio.&lt;/p&gt;

&lt;p&gt;Recordemos el &lt;em&gt;plugin&lt;/em&gt; de Notificaci&amp;oacute;n de Excepciones que vimos en el  &lt;a href="http://railscasts.com/episodes/104-exception-notifications"&gt;Episodio 104&lt;/a&gt; y que se pod&amp;iacute;a a&amp;ntilde;adir a una aplicaci&amp;oacute;n para almacenar en la base de datos todas las excepciones que ocurriesen.  Tambi&amp;eacute;n proporcionaba una interfaz de usuario que permit&amp;iacute;a mostrar las excepciones.  En este episodio reescribiremos dicho &lt;em&gt;plugin&lt;/em&gt; como un &lt;em&gt;engine&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;Empezando&lt;/h3&gt;

&lt;p&gt;Antes de empezar a escribir nuestro &lt;em&gt;engine&lt;/em&gt; tenemos que asegurarnos de estar con la versi&amp;oacute;n candidata 5 de Rails 3.1, podemos hacerlo con&lt;/p&gt;

&lt;pre class="terminal"&gt;$ gem install rails --pre&lt;/pre&gt;

&lt;p&gt;Una vez que tengamos instalada la versi&amp;oacute;n adecuada de Rails podemos empezar a generar nuestro &lt;em&gt;engine&lt;/em&gt;.  No tenemos por qu&amp;eacute; crearlo dentro de una aplicaci&amp;oacute;n Rails: de hecho, la creaci&amp;oacute;n de un &lt;em&gt;engine&lt;/em&gt; es muy parecida  a la creaci&amp;oacute;n de una aplicaci&amp;oacute;n Rails normal, incluyendo la generaci&amp;oacute;n del c&amp;oacute;digo porque la &amp;uacute;nica diferencia es que ejecutaremos &lt;code&gt;rails plugin new&lt;/code&gt; en lugar de &lt;code&gt;rails new&lt;/code&gt;.  Como nuestro &lt;em&gt;engine&lt;/em&gt; gestiona excepciones, lo llamaremos &lt;code&gt;uhoh&lt;/code&gt;.  Tenemos que pasar la opci&amp;oacute;n &lt;code&gt;--mountable&lt;/code&gt; para que sea un &lt;em&gt;engine&lt;/em&gt; que se pueda montar sobre otras aplicaciones.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails plugin new uhoh --mountable&lt;/pre&gt;

&lt;p&gt;La estructura de directorios de la aplicaci&amp;oacute;n tiene todo el aspecto de una aplicaci&amp;oacute;n Rails normal y b&amp;aacute;sicamente lo es, s&amp;oacute;lo que est&amp;aacute; dise&amp;ntilde;ada para ser montada sobre otra aplicaci&amp;oacute;n por lo que hay algunas diferencias.  Hay varios directorios con su propio espacio de nombres, por ejemplo el fichero &lt;code&gt;application_controller&lt;/code&gt; vive dentro de &lt;code&gt;/app/controllers/uhoh&lt;/code&gt; y lo mismo sucede con los ficheros debajo de &lt;code&gt;assets&lt;/code&gt;, &lt;code&gt;helpers&lt;/code&gt; y &lt;code&gt;views&lt;/code&gt;  Esto hace que el c&amp;oacute;digo del &lt;em&gt;engine&lt;/em&gt; quede limpiamente separado del resto de la aplicaci&amp;oacute;n dentro de la que vivir&amp;aacute;.  Como ya existe un directorio en &lt;code&gt;assets&lt;/code&gt; esto quiere decir que ya no tenemos que preocuparnos de copiar los recursos est&amp;aacute;ticos al directorio &lt;code&gt;/public&lt;/code&gt; cuando montamos el &lt;em&gt;engine&lt;/em&gt; dentro de la aplicaci&amp;oacute;n.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/712/original/E277I01.png" width="800" height="502" alt="La estructura de directorios que tiene el &lt;em&gt;engine&lt;/em&gt;."/&gt;
&lt;/div&gt;

&lt;p&gt;Los recursos est&amp;aacute;ticos tambi&amp;eacute;n tienen su propio espacio de nombres as&amp;iacute; que cuando los enlacemos tendremos que hacerlo a trav&amp;eacute;s de dicho directorio.  Podemos ver esto tambi&amp;eacute;n en la carpeta de &lt;em&gt;layouts&lt;/em&gt;, aunque parece que todav&amp;iacute;a queda alg&amp;uacute;n error en la RC5 porque tenemos dos &lt;code&gt;application.html.erb&lt;/code&gt;.  Podemos borrar con tranquilidad el que est&amp;aacute; fuera de la carpeta &lt;code&gt;uhoh&lt;/code&gt;.  Si abrimos el otro veremos que las referencias a los recursos llevan todas el directorio extra &lt;code&gt;uhoh&lt;/code&gt;.  Siempre que enlacemos a im&amp;aacute;genes u otros recursos tenemos que hacerlo a trav&amp;eacute;s de dicho espacio de nombres.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/app/views/layouts/uhoh/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;Uhoh&amp;lt;/title&amp;gt;
  &amp;lt;%= stylesheet_link_tag    &amp;quot;uhoh/application&amp;quot; %&amp;gt;
  &amp;lt;%= javascript_include_tag &amp;quot;uhoh/application&amp;quot; %&amp;gt;
  &amp;lt;%= csrf_meta_tags %&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;%= yield %&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;

&lt;p&gt;A continuaci&amp;oacute;n veremos uno de los ficheros clave llamado &lt;code&gt;engine.rb&lt;/code&gt; que se encuentra en la carpeta &lt;code&gt;/lib/uhoh&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/lib/uhoh/engine.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;module Uhoh
  class Engine &amp;lt; Rails::Engine
    isolate_namespace Uhoh
  end
end&lt;/pre&gt;

&lt;p&gt;Se trata de una clase que hereda de &lt;code&gt;Rails::Engine&lt;/code&gt; y es donde ocurre toda la configuraci&amp;oacute;n personalizada.  Ya existe una llamada a &lt;code&gt;isolate_namespace&lt;/code&gt; en esta clase, lo que significa que el &lt;em&gt;engine&lt;/em&gt; ser&amp;aacute; considerado como su propia unidad aislada y no tendr&amp;aacute; que preocuparse de la aplicaci&amp;oacute;n en la que se encuentre montado.&lt;/p&gt;

&lt;p&gt;La parte final del &lt;em&gt;engine&lt;/em&gt; es el directorio &lt;code&gt;/test&lt;/code&gt;.  Bajo &lt;code&gt;/test/dummy&lt;/code&gt; hay una aplicaci&amp;oacute;n Rails que est&amp;aacute; ah&amp;iacute; para que veamos c&amp;oacute;mo funciona nuestro &lt;em&gt;engine&lt;/em&gt; cuando se monta sobre otra aplicaci&amp;oacute;n.  El directorio &lt;code&gt;config/&lt;/code&gt; de dicha aplicaci&amp;oacute;n contiene un fichero &lt;code&gt;routes.rb&lt;/code&gt;, con la llamada a &lt;code&gt;mount&lt;/code&gt; en la que se pasa la clase principal del &lt;em&gt;engine&lt;/em&gt; asign&amp;aacute;ndola a una ruta.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/test/dummy/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;Rails.application.routes.draw do
  mount Uhoh::Engine =&amp;gt; &amp;quot;/uhoh&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Esto es exactamente lo que cualquiera que quiera instalar el &lt;em&gt;engine&lt;/em&gt; en una aplicaci&amp;oacute;n tendr&amp;aacute; que hacer, montarla en la ruta que escoja.  Se trata de una aplicaci&amp;oacute;n Rack por lo que si una petici&amp;oacute;n llega a &lt;code&gt;/uhoh&lt;/code&gt; ser&amp;aacute; nuestra clase &lt;code&gt;Engine&lt;/code&gt; quien la reciba.  No es mala idea a&amp;ntilde;adir esta l&amp;iacute;nea a las instrucciones de instlaci&amp;oacute;n en el fichero README de la clase para que los usuarios sepan c&amp;oacute;mo montarla en el fichero de rutas de su aplicaci&amp;oacute;n.&lt;/p&gt;

&lt;p&gt;La aplicaci&amp;oacute;n de pruebas sirve tambi&amp;eacute;n para probar manualmente el &lt;em&gt;engine&lt;/em&gt;, aunque se encuentre en el directorio &lt;code&gt;test&lt;/code&gt;.  Podemos ejecutar la aplicaci&amp;oacute;n de prueba ejecutando &lt;code&gt;rails s&lt;/code&gt; en el directorio de nuestro &lt;em&gt;engine&lt;/em&gt;.  Y si visitamos &lt;a href="http://localhost:3000/uhoh/"&gt;&lt;code&gt;http://localhost:3000/uhoh/&lt;/code&gt;&lt;/a&gt; iremos al &lt;em&gt;engine&lt;/em&gt; porque hemos cargado la URL en la que se encuentra montado.  Sin embargo aparecer&amp;aacute; un error al cargar dicha p&amp;aacute;gina porque no hemos escrito todav&amp;iacute;a ning&amp;uacute;n controlador.&lt;/p&gt;

&lt;p&gt;A continuaci&amp;oacute;n crearemos un controlador &lt;code&gt;failures&lt;/code&gt;.  Podemos usar los generadores de Rails igual que en una aplicaci&amp;oacute;n normal.  Aunque estamos en un &lt;em&gt;engine&lt;/em&gt; no tenemos por qu&amp;eacute; explicitar el espacio de nombres ya que &amp;eacute;sto se gestiona autom&amp;aacute;ticamente.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g controller failures index&lt;/pre&gt;

&lt;p&gt;Esta orden genera los mismos archivos que con un controlador normal, excepto que todo se coloca autom&amp;aacute;ticamente en el directorio correspondiente al espacio de nombres adecuado.  A continuaci&amp;oacute;n modificaremos las rutas del &lt;em&gt;engine&lt;/em&gt; para tener una ruta &lt;code&gt;root&lt;/code&gt; a la acci&amp;oacute;n &lt;code&gt;index&lt;/code&gt; del controlador.  Esto se hace en el fichero &lt;code&gt;/config/routes&lt;/code&gt; del &lt;em&gt;engine&lt;/em&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;Uhoh::Engine.routes.draw do
  root :to =&amp;gt; &amp;quot;failures#index&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Si visitamos  &lt;a href="http://localhost:3000/uhoh/"&gt;&lt;code&gt;http://localhost:3000/uhoh/&lt;/code&gt;&lt;/a&gt; veremos la vista de la acci&amp;oacute;n.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/713/original/E277I02.png" width="801" height="280" alt="The default text in the index view."/&gt;
&lt;/div&gt;

&lt;p&gt;En esta p&amp;aacute;gina queremos mostrar un listado con las excepciones que han ocurrido.  Necesitamos un modelo para guardar esta informaci&amp;oacute;n, por lo que crearemos el modelo &lt;code&gt;Failure&lt;/code&gt; que s&amp;oacute;lo tendr&amp;aacute; un campo para el mensaje de la excepci&amp;oacute;n.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g model failure message:text&lt;/pre&gt;

&lt;p&gt;Con este modelo ya creado, &amp;iquest;c&amp;oacute;mo ejecutamos las migraciones?  Dentro del propio &lt;em&gt;engine&lt;/em&gt; podemos ejecutar normalmente &lt;code&gt;rake db:migrate&lt;/code&gt; y todo funcionar&amp;aacute; como ser&amp;iacute;a de esperar.  Pero cuando el &lt;em&gt;engine&lt;/em&gt; se encuentre montado sobre otra aplicaci&amp;oacute;n esto no funcionar&amp;aacute; porque la tarea &lt;code&gt;rake&lt;/code&gt; no coger&amp;aacute; las migraciones que se encuentren dentro de los &lt;em&gt;engines&lt;/em&gt;.  Tendremos que especificar a los usuarios de nuestro &lt;em&gt;engine&lt;/em&gt; que deben ejecutar la tarea &lt;code&gt;rake uhoh:install:migrations&lt;/code&gt;, que copiar&amp;aacute; las migraciones del &lt;em&gt;engine&lt;/em&gt; junto con las de la aplicaci&amp;oacute;n de forma que se ejecuten cuando se lanza &lt;code&gt;rake db:migrate&lt;/code&gt; como es habitual.  Es buena idea incluir esta informaci&amp;oacute;n en las instrucciones de instalaci&amp;oacute;n.&lt;/p&gt;

&lt;p&gt;La consola de Rails tambi&amp;eacute;n funciona como cabr&amp;iacute;a esperar, por lo que la utilizaremos para crear un &lt;code&gt;Failure&lt;/code&gt; de ejemplo.&lt;/p&gt;


&lt;pre class="ruby"&gt;Uhoh::Failure.create!(:message =&amp;gt; &amp;quot;hello world!&amp;quot;)&lt;/pre&gt;

&lt;p&gt;Obs&amp;eacute;rvese que tenemos que incluir el espacio de nombre siempre que hagamos referencia a una de las clases.  Ahora que tenemos un registro &lt;code&gt;Failure&lt;/code&gt; lo mostraremos en la acci&amp;oacute;n &lt;code&gt;index&lt;/code&gt; de nuestro &lt;code&gt;failuresController&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/uhoh/failures_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;module Uhoh
  class FailuresController &amp;lt; ApplicationController
    def index
      @failures = Failure.all
    end
  end
end&lt;/pre&gt;

&lt;p&gt;Al contrario de cuando estamos en la consola no tenemos que especificar un espacio de nombres, porque ya estamos dentro del m&amp;oacute;dulo &lt;code&gt;Uhoh&lt;/code&gt;.  En la vista escribiremos el c&amp;oacute;digo necesario para iterar sobre todos los errores y mostrarlos en una lista.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/uhoh/failures/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;h1&amp;gt;Failures&amp;lt;/h1&amp;gt;
&amp;lt;ul&amp;gt;
  &amp;lt;% for failure in @failures %&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= failure.message %&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/pre&gt;

&lt;p&gt;Cuando recarguemos la p&amp;aacute;gina veremos el mensaje &lt;code&gt;Failure&lt;/code&gt; que acabamos de a&amp;ntilde;adir.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/714/original/E277I03.png" width="801" height="280" alt="Ahora el error aparece en el listado."/&gt;
&lt;/div&gt;

&lt;h3&gt;Captura de excepciones&lt;/h3&gt;

&lt;p&gt;Ya tenemos una manera de guardar los errores, ahora s&amp;oacute;lo tenemos que usarla cada vez que ocurra una excepci&amp;oacute;n en la aplicaci&amp;oacute;n sobre la que hayamos montado nuestro &lt;em&gt;engine&lt;/em&gt;.  Para probar esto tenemos que poder simular una excepci&amp;oacute;n en la aplicaci&amp;oacute;n de prueba, para lo que nos moveremos al directorio de la aplicaci&amp;oacute;n de prueba y generaremos un controlador llamado &lt;code&gt;simulate&lt;/code&gt; con una acci&amp;oacute;n &lt;code&gt;failure&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g controller simulate failure&lt;/pre&gt;

&lt;p&gt;En la acci&amp;oacute;n elevaremos una excepci&amp;oacute;n.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/test/dummy/app/controllers/simulate_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class SimulateController &amp;lt; ApplicationController
  def failure
    raise &amp;quot;Simulating an exception&amp;quot;
  end
end&lt;/pre&gt;

&lt;p&gt;Si visitamos con el navegador dicha acci&amp;oacute;n veremos, como era de esperar, la excepci&amp;oacute;n.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/715/original/E277I04.png" width="800" height="420" alt="La excepci&#243;n tal y como aparece en el navegador."/&gt;
&lt;/div&gt;

&lt;p&gt;Tenemos que cambiar el &lt;em&gt;engine&lt;/em&gt; de forma que est&amp;eacute; pendiente de dicha excepci&amp;oacute;n y cree en ese momento un nuevo registro &lt;code&gt;Failure&lt;/code&gt;.  La soluci&amp;oacute;n que proponemos no es especialmente eficiente pero al menos es sencilla y servir&amp;aacute;  como ejemplo.  Empezaremos creando un inicializador en el &lt;em&gt;engine&lt;/em&gt;, aunque no exista un directorio &lt;code&gt;initializers&lt;/code&gt; en el directorio &lt;code&gt;config&lt;/code&gt; de nuestro &lt;em&gt;engine&lt;/em&gt; lo podemos crear.  En este directorio pondremos un fichero llamado &lt;code&gt;exception_handler.rb&lt;/code&gt;.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/app/config/initializers/exception_handler.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveSupport::Notifications.subscribe &amp;crarr;
  &amp;quot;process_action.action_controller&amp;quot; do &amp;crarr;
  |name, start, finish, id, payload|
  if payload[:exception]
    name, message = *payload[:exception]
    Uhoh::Failure.create!(:message =&amp;gt; message)
  end
end&lt;/pre&gt;

&lt;p&gt;En este fichero nos suscribimos a una notificaci&amp;oacute;n (vimos las notificaciones en el episodio 249 [&lt;a href="http://railscasts.com/episodes/249-notifications-in-rails-3"&gt;verlo&lt;/a&gt;, &lt;a href="http://asciicasts.com/episodes/249-notifications-in-rails-3"&gt;leerlo&lt;/a&gt;]).  Dicha notificaci&amp;oacute;n nos indica que se ha terminado de procesar una acci&amp;oacute;n.  En este momento es cuando podemos comprobar si el atributo &lt;code&gt;payload&lt;/code&gt; contiene una excepci&amp;oacute;n en cuyo caso sabemos que se ha elevado una excepci&amp;oacute;n  y podemos guardar el mensaje en su correspondiente &lt;code&gt;Failure&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para probarlo tenemos que reiniciar el servidor.  Podemos visitar  &lt;a href="http://localhost:3000/simulate/failure"&gt;&lt;code&gt;http://localhost:3000/simulate/failure&lt;/code&gt;&lt;/a&gt; para que se lance la excepci&amp;oacute;n.  Si luego vamos a  &lt;a href="http://localhost:3000/uhoh"&gt;&lt;code&gt;http://localhost:3000/uhoh&lt;/code&gt;&lt;/a&gt; encontraremos que dicha excepci&amp;oacute;n ha quedado registrada.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/716/original/E277I05.png" width="800" height="420" alt="La excepci&#243;n aparece en el listado."/&gt;
&lt;/div&gt;

&lt;h3&gt;Gesti&amp;oacute;n de URLs en los &lt;em&gt;engines&lt;/em&gt;.&lt;/h3&gt;

&lt;p&gt;Los &lt;em&gt;helpers&lt;/em&gt; de URL que se utilicen dentro de un &lt;em&gt;engine&lt;/em&gt; generar&amp;aacute;n URLs para dicho &lt;em&gt;engine&lt;/em&gt;.  Por ejemplo si se a&amp;ntilde;ade un enlace a la URL ra&amp;iacute;z desde nuestra vista &lt;code&gt;index&lt;/code&gt;, el enlace apuntar&amp;aacute; a la URL del &lt;em&gt;engine&lt;/em&gt;, no a la de la aplicaci&amp;oacute;n en la que se ha montado.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/uhoh/failures/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Failures&amp;quot;, root_url %&amp;gt;&amp;lt;/p&amp;gt;&lt;/pre&gt;

&lt;p&gt;El enlace apunta a &lt;a href="http://localhost:3000/uhoh"&gt;&lt;code&gt;http://localhost:3000/uhoh&lt;/code&gt;&lt;/a&gt; que es la URL ra&amp;iacute;z del &lt;em&gt;engine&lt;/em&gt;.  En este caso se trata de la misma p&amp;aacute;gina porque la URL ra&amp;iacute;z se define en las rutas del &lt;em&gt;engine&lt;/em&gt; como la acci&amp;oacute;n &lt;code&gt;index&lt;/code&gt; de &lt;code&gt;FailuresController&lt;/code&gt;.  Podemos crear enlaces a la aplicaci&amp;oacute;n propiamente dicha utilizando el prefijo &lt;code&gt;main_app&lt;/code&gt; de la siguiente manera:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/uhoh/failures/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Failures&amp;quot;, root_url %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Simulate Failure&amp;quot;, main_app.simulate_failure_path %&amp;gt;&amp;lt;/p&amp;gt;&lt;/pre&gt;

&lt;p&gt;Con esto tenemos un enlace a la p&amp;aacute;gina de simulaci&amp;oacute;n de excepciones, que se encuentra en  &lt;a href="http://localhost:3000/simulate/failure"&gt;&lt;code&gt;http://localhost:3000/simulate/failure&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt; 

&lt;p&gt;&amp;iquest;Y si lo que queremos es justo lo contrario, tener un enlace al &lt;em&gt;engine&lt;/em&gt; desde la aplicaci&amp;oacute;n principal?  Lo primero que tenemos que hacer es cambiar la l&amp;iacute;nea en el fichero de rutas donde montamos el &lt;em&gt;engine&lt;/em&gt; y darle un nombre utilizando la opci&amp;oacute;n &lt;code&gt;:as&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/test/dummy/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;Rails.application.routes.draw do

  get &amp;quot;simulate/failure&amp;quot;

  mount Uhoh::Engine =&amp;gt; &amp;quot;/uhoh&amp;quot;, :as =&amp;gt; &amp;quot;uhoh_engine&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Tras esto podemos acceder a los &lt;em&gt;helpers&lt;/em&gt; de URL del &lt;em&gt;engine&lt;/em&gt; como m&amp;eacute;todos de &lt;code&gt;uhoh_engine&lt;/code&gt;.  Para demostrar esto vamos a cambiar temporalmente nuestra acci&amp;oacute;n que genera excepciones para que en lugar de elevar la excepci&amp;oacute;n redirija a la URL ra&amp;iacute;z del &lt;em&gt;engine&lt;/em&gt;.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/test/dummy/app/controllers/simulate_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class SimulateController &amp;lt; ApplicationController
  def failure
    redirect_to uhoh_engine.root_url
  end
end&lt;/pre&gt;

&lt;p&gt;Si ahora visitamos  &lt;a href="http://localhost:3000/simulate/failure"&gt;&lt;code&gt;http://localhost:3000/simulate/failure&lt;/code&gt;&lt;/a&gt; seremos redirigidos a &lt;a href="http://localhost:3000/uhoh"&gt;&lt;code&gt;http://localhost:3000/uhoh&lt;/code&gt;&lt;/a&gt; porque estamos usando el &lt;em&gt;helper&lt;/em&gt; de dicho &lt;em&gt;engine&lt;/em&gt; para generar la URL.  Esta es otra funcionalidad que cabe mencionar en el fichero &lt;code&gt;README&lt;/code&gt; de nuestro &lt;em&gt;engine&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Con todo esto ya tenemos la funcionalidad de nuestro &lt;em&gt;engine&lt;/em&gt; pr&amp;aacute;cticamente completa, pero la p&amp;aacute;gina que muestra los errores tiene un aspecto muy sobrio, por lo que le pondremos varios adornos.  Primero a&amp;ntilde;adiremos una imagen, que pondremos en el directorio &lt;code&gt;/app/assets/images/uhoh&lt;/code&gt;, y para incluirla en la p&amp;aacute;gina podemos usar &lt;code&gt;image_tag&lt;/code&gt; igual que con cualquier otra imagen.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/uhoh/failures/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;%= image_tag &amp;quot;uhoh/alert.png&amp;quot; %&amp;gt;
&amp;lt;h1&amp;gt;Failures&amp;lt;/h1&amp;gt;
&amp;lt;ul&amp;gt;
  &amp;lt;% for failure in @failures %&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= failure.message %&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Failures&amp;quot;, root_url %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Simulate Failure&amp;quot;, &amp;crarr;
  main_app.simulate_failure_path %&amp;gt;&amp;lt;/p&amp;gt;&lt;/pre&gt;

&lt;p&gt;Incluyamos tambi&amp;eacute;n algo de CSS.  SASS y CoffeeScript no pueden usarse por defecto en los &lt;em&gt;engine&lt;/em&gt; pero se pueden a&amp;ntilde;adir como dependencias.  Si a&amp;ntilde;adimos CSS al fichero &lt;code&gt;failures.css&lt;/code&gt; &amp;eacute;ste se incluir&amp;aacute; autom&amp;aacute;ticamente.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/uhoh/failures.css&lt;/p&gt;
&lt;pre class="css"&gt;html, body {
  background-color: #DDD;
  font-family: Verdana;
}

body {
  padding: 20px 200px;
}

img {
  display: block;
  margin: 0 auto;
}

a {
  color: #000;
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

li {
  background-color: #FFF;
  margin-bottom: 10px;
  padding: 5px 10px;
}&lt;/pre&gt;

&lt;p&gt;Lo mismo con el JavaScript.  El c&amp;oacute;digo que incluyamos en &lt;code&gt;failures.js&lt;/code&gt; se incluir&amp;aacute; autom&amp;aacute;ticamente.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/app/assets/javascripts/uhoh/failures.js&lt;/p&gt;
&lt;pre class="javascript"&gt;$(function() {
  $(&amp;quot;li&amp;quot;).click(function() {
    $(this).slideUp();
  });
});&lt;/pre&gt;

&lt;p&gt;Si ahora recargamos la p&amp;aacute;gina tendr&amp;aacute; mucho mejor aspecto, y podemos ocultar la excepci&amp;oacute;n haciendo clic en ella, con lo que sabemos que el JavaScript ha sido incorporado correctamente.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/717/original/E277I06.png" width="799" height="436" alt="Nuestra p&#225;gina de errores con CSS y JavaScript."/&gt;
&lt;/div&gt;

&lt;p&gt;Con esto terminamos este episodio.  La posibilidad de montar &lt;em&gt;engines&lt;/em&gt; es una gran funcionalidad de Rails 3.1, que merece la pena estudiar.&lt;/p&gt;
</description>
      <pubDate>Sat, 10 Sep 2011 20:38:23 +0000</pubDate>
      <guid>http://es.asciicasts.com/episodes/277-engines-montables</guid>
      <link>http://es.asciicasts.com/episodes/277-engines-montables</link>
    </item>
    <item>
      <title>Tests dependientes de la hora y peticiones web externas</title>
      <description>&lt;p&gt;En el episodio anterior vimos como seguir un proceso de desarrollo basado en tests.  Esta forma de trabajo funciona bien por lo general pero hay veces en que las aplicaciones tendr&amp;aacute;n funcionalidades especialmente dif&amp;iacute;ciles de probar.  Veamos dos de estos escenarios en este episodio.&lt;/p&gt;

&lt;h3&gt;Tests sobre la hora actual&lt;/h3&gt;

&lt;p&gt;Recordemos que en el otro episodio cre&amp;aacute;bamos un n&amp;uacute;mero de pruebas sobre el modelo &lt;code&gt;User&lt;/code&gt;.  Las escribimos muy deprisa as&amp;iacute; que volveremos a una de las especificaciones para inspeccionarla.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/spec/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;it &amp;quot;saves the time the password reset was sent&amp;quot; do
  user.send_password_reset
  user.reload.password_reset_sent_at.should be_present
end&lt;/pre&gt;

&lt;p&gt;En este test se comprueba que cuando se env&amp;iacute;a un mensaje de restablecimiento de contrase&amp;ntilde;a la hora de env&amp;iacute;o queda guardada en el campo &lt;code&gt;password_reset_sent_at&lt;/code&gt; de la base de datos utilizando la funci&amp;oacute;n &lt;code&gt;be_present&lt;/code&gt; de RSpec, que llama al m&amp;eacute;todo &lt;code&gt;present?&lt;/code&gt; de Rails que comprueba la existencia de un objeto.&lt;/p&gt;

&lt;p&gt;Pero este test est&amp;aacute; incompleto: comprueba que existe el valor de &lt;code&gt;password_reset_sent_at&lt;/code&gt; pero no que tenga la hora correcta.  Establecemos &lt;code&gt;password_reset_sent_at&lt;/code&gt; a &lt;code&gt;Time.zone.now&lt;/code&gt; en el m&amp;eacute;todo &lt;code&gt;send_password_reset&lt;/code&gt; del modelo pero la especificaci&amp;oacute;n pasar&amp;iacute;a independientemente del valor que pusi&amp;eacute;semos aqu&amp;iacute;.  Idealmente deber&amp;iacute;amos comprobar que el valor es correcto con algo parecido a:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;it &amp;quot;saves the time the password reset was sent&amp;quot; do
  user.send_password_reset
  user.reload.password_reset_sent_at.should eq(Time.zone.now)
end&lt;/pre&gt;

&lt;p&gt;Por desgracia este enfoque no funciona.  La hora actual en el instante en que se ejecuta la especificaci&amp;oacute;n ser&amp;aacute; ligeramente distinta de la hora cuando actual cuando se ejecute la l&amp;iacute;nea siguiente.  Ante un problema como este merece la pena preguntarse si nos compensa meter m&amp;aacute;s complejidad en el test para probar un caso como este, donde parece razonable pensar que basta con comprobar la presencia del valor de tiempo dado que hay muy poca posibilidad de que se ponga la hora incorrecta en la &amp;uacute;nica l&amp;iacute;nea de c&amp;oacute;digo que lo hace.  Sin embargo hay veces que nos interesa hacer pruebas sobre la hora actual as&amp;iacute; que investigaremos c&amp;oacute;mo hacerlo.&lt;/p&gt;

&lt;p&gt;Tenemos Guard ejecut&amp;aacute;ndose y podemos ver que falla la especificaci&amp;oacute;n.  Aunque los valores de tiempo son id&amp;eacute;nticos hasta el segundo, no son exactamente iguales y esto es suficiente para hacer que falle la especificaci&amp;oacute;n.&lt;/p&gt;


&lt;pre class="terminal"&gt;Failures:

  1) User#send_password_reset saves the time the password reset was sent
     Failure/Error: user.reload.password_reset_sent_at.should eq(Time.zone.now)
       
       expected Mon, 25 Jul 2011 20:34:46 UTC +00:00
            got Mon, 25 Jul 2011 20:34:46 UTC +00:00
       
       (compared using ==)
       
       Diff:
     # ./spec/models/user_spec.rb:16:in `block (3 levels) in &amp;lt;top (required)&amp;gt;&amp;#x27;

Finished in 1.95 seconds
9 examples, 1 failure&lt;/pre&gt;

&lt;p&gt;Para este tipo de problemas podemos usar  &lt;a href="https://github.com/jtrupiano/timecop/"&gt;Timecop&lt;/a&gt;, con la que podemosmanipular la hora actual de diferentes maneras, pudiendo incluso congelarla.  Esto quiere decir que podemos congelar el tiempo durante el tiempo que se ejecuta el test de forma que el momento en que se genera el valor de tiempo ser&amp;aacute; el mismo que cuando se comprueba que sea el correcto.&lt;/p&gt;

&lt;p&gt;Timecop se incorpora en nuestra aplicaci&amp;oacute;n a&amp;ntilde;adi&amp;eacute;ndolo al &lt;code&gt;Gemfile&lt;/code&gt; y ejecutando &lt;code&gt;bundle&lt;/code&gt;.  Como s&amp;oacute;lo lo necesitamos para los tests lo a&amp;ntilde;adiremos al grupo &lt;code&gt;test&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;source &amp;#x27;http://rubygems.org&amp;#x27;

gem &amp;#x27;rails&amp;#x27;, &amp;#x27;3.1.0.rc4&amp;#x27;

gem &amp;#x27;sqlite3&amp;#x27;

# Asset template engines
gem &amp;#x27;sass-rails&amp;#x27;, &amp;quot;~&amp;gt; 3.1.0.rc&amp;quot;
gem &amp;#x27;coffee-script&amp;#x27;
gem &amp;#x27;uglifier&amp;#x27;

gem &amp;#x27;jquery-rails&amp;#x27;

gem &amp;quot;rspec-rails&amp;quot;, :group =&amp;gt; [:test, :development]
group :test do
  gem &amp;quot;factory_girl_rails&amp;quot;
  gem &amp;quot;capybara&amp;quot;
  gem &amp;quot;guard-rspec&amp;quot;
  gem &amp;quot;timecop&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Es buena idea ir al fichero &lt;code&gt;spec_helper&lt;/code&gt; y a&amp;ntilde;adir una llamada a &lt;code&gt;Timecop.return&lt;/code&gt; en el bloque &lt;code&gt;config.before(:each)&lt;/code&gt; de esta forma los cambios que hagamos con Timecop dejar&amp;aacute;n de surtir efecto antes de ejecutar la siguiente especificaci&amp;oacute;n.&lt;/p&gt;

&lt;p&gt;Ya podemos invocar a &lt;code&gt;Timecop.freeze&lt;/code&gt; en cualquier de los tests y el tiempo se parar&amp;aacute; durante su ejecuci&amp;oacute;n.  Esto significa que ya podemos comparar los instantes de tiempo:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;it &amp;quot;saves the time the password reset was sent&amp;quot; do
  Timecop.freeze
  user.send_password_reset
  user.reload.password_reset_sent_at.should eq(Time.zone.now)
end&lt;/pre&gt;

&lt;p&gt;Cuando Guard ejecute las especificaciones, &amp;eacute;stas pasar&amp;aacute;n correctamente.&lt;/p&gt;

&lt;p&gt;Existe otro escenario inesperado que puede hacer que los tests fallen.  Por ejemplo si vamos a una conferencia de Ruby en una zona horaria diferente nos podemos encontrar con que de repente los tests relacionados con la fecha fallan.  En lugar de recorrer medio mundo de vuelta resultar&amp;aacute; m&amp;aacute;s barato establecer la zona horaria correspondiente en las especificaciones.  Esto se hace estableciendo &lt;code&gt;Time.zone&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;Time.zone = &amp;quot;Paris&amp;quot;&lt;/pre&gt;

&lt;p&gt;Para establecer temporalmente la zona horaria dentro de un &amp;uacute;nico test podemos llamar a &lt;code&gt;Time.use_zone&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/model/user_spec.rb&lt;/p&gt;

&lt;pre class="ruby"&gt;it &amp;quot;saves the time the password reset was sent&amp;quot; do
  Timecop.freeze
  user.send_password_reset
  Time.use_zone(&amp;quot;Paris&amp;quot;) do
    user.reload.password_reset_sent_at.should eq(Time.zone.now)
  end
end&lt;/pre&gt;

&lt;p&gt;El c&amp;oacute;digo dentro del bloque se ejecutar&amp;aacute; como si estuvi&amp;eacute;semos en Par&amp;iacute;s.  Podemos aprovechar esto para comprobar que las especificaciones siguen pasando aunque estemos en una zona horaria diferente.&lt;/p&gt;

&lt;p&gt;Siempre que escribamos tests que dependan de la hora actual deber&amp;iacute;amos utilizar algo como Timecop para comproba que la fecha se utiliza de forma consistente y que la funcionalidad no cambia si lo hace la zona horaria de nuestro equipo o durante el horario de verano, con lo que adem&amp;aacute;s podemos comprobar que nuestra aplicaci&amp;oacute;n funcionar&amp;aacute; en todo el mundo.&lt;/p&gt;

&lt;h3&gt;Peticiones de web externas&lt;/h3&gt;

&lt;p&gt;A continuaci&amp;oacute;n vamos a ver c&amp;oacute;mo escribir tests que hacen peticiones a web externas.  Esta secci&amp;oacute;n est&amp;aacute; basada en un problema que se encontr&amp;oacute; Ryan Bates cuando reescribi&amp;oacute; la web de Railscasts, espec&amp;iacute;ficamente la funcionalidad de mostrar el tama&amp;ntilde;o de archivo para cada v&amp;iacute;deo cuando se pasa el rat&amp;oacute;n sobre el enlace de descarga.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/708/original/E276I01.png" width="798" height="411" alt="Se muestra el tama&#241;o del archivo para cada formato de video."/&gt;
&lt;/div&gt;

&lt;p&gt;Como los archivos se encuentran alojados en un servidor externo, hay que lanzar una petici&amp;oacute;n web externa para calcular su tama&amp;ntilde;o.  Veamos c&amp;oacute;mo se escribieron los tests para esto utilizando el ejemplo de una peque&amp;ntilde;a aplicaci&amp;oacute;n.  Tiene un recurso WebRequest y un formulario con un campo de texto que recibe una URL.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/709/original/E276I02.png" width="800" height="322" alt="Una aplicaci&#243;n que hace peticiones web."/&gt;
&lt;/div&gt;

&lt;p&gt;Cuando se introduce la URL de un video en la caja de texto y se env&amp;iacute;a el formulario, se muestra la URL as&amp;iacute; como el tama&amp;ntilde;o del archivo que como puede verse tiene cero bytes.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/710/original/E276I03.png" width="800" height="322" alt="Siempre aparecen 0 bytes de tama&#241;o."/&gt;
&lt;/div&gt;

&lt;p&gt;El tama&amp;ntilde;o de archivo es cero porque todav&amp;iacute;a no hemos implementado esta funcionalidad.  Tenemos un m&amp;eacute;todo &lt;code&gt;content_length&lt;/code&gt; en nuestro modelo &lt;code&gt;WebRequest&lt;/code&gt; que est&amp;aacute; forzado para devolver siempre &lt;code&gt;0&lt;/code&gt;.  Implementemos este m&amp;eacute;todo usando TDD.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/web_request.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class WebRequest &amp;lt; ActiveRecord::Base
  def content_length
    0
  end
end&lt;/pre&gt;

&lt;p&gt;Tenemos varias gemas con las que escribir tests de peticiones web externas, pero nosotros vamos a usar  &lt;a href="https://github.com/chrisk/fakeweb"&gt;Fakeweb&lt;/a&gt;. Esta gema puede usarse para registrar una URL y definir cu&amp;aacute;l es la respuesta que se debe devolver cuando se utilice &lt;code&gt;Net::HTTP&lt;/code&gt; para recuperar dicha URL.  Por lo tanto, &lt;code&gt;Net::HTTP&lt;/code&gt; no lanzar&amp;aacute; la petici&amp;oacute;n real sino que devolver&amp;aacute; lo que hayamos establecido.&lt;/p&gt;

&lt;p&gt;Fakeweb se instala de la forma habitual, a&amp;ntilde;adi&amp;eacute;ndolo al &lt;code&gt;Gemfile&lt;/code&gt; y ejecutando &lt;code&gt;bundle&lt;/code&gt;.  A continuaci&amp;oacute;n a&amp;ntilde;adiremos la configuraci&amp;oacute;n de Fakeweb haciendo dos cambios en el archivo &lt;code&gt;spec_helper&lt;/code&gt;.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/spec/spec_helper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ENV[&amp;quot;RAILS_ENV&amp;quot;] ||= &amp;#x27;test&amp;#x27;
require File.expand_path(&amp;quot;../../config/environment&amp;quot;, __FILE__)
require &amp;#x27;rspec/rails&amp;#x27;
require &amp;#x27;capybara/rspec&amp;#x27;

Dir[Rails.root.join(&amp;quot;spec/support/**/*.rb&amp;quot;)].each {|f| require f}

FakeWeb.allow_net_connect = false

RSpec.configure do |config|
  config.mock_with :rspec
  config.use_transactional_fixtures = true
  config.include(MailerMacros)
  config.before(:each) do
    Timecop.return
    reset_email 
    FakeWeb.clean_registry
  end
end&lt;/pre&gt;

&lt;p&gt;En la parte superior del archivo establecemos &lt;code&gt;Fakeweb.allow_net_connect&lt;/code&gt; a &lt;code&gt;false&lt;/code&gt;, lo que hace que las especificaciones no lancen ninguna conexi&amp;oacute;n externa HTTP.  Esto es &amp;uacute;til porque quiere decir que si hemos dejado otras peticiones web en las especificaciones, &amp;eacute;stas no ralentizaran la suite, y Fakeweb nos avisar&amp;aacute; que la especificaci&amp;oacute;n se est&amp;aacute; conectando a la web.  En &lt;code&gt;before(:each)&lt;/code&gt; invocamos a &lt;code&gt;Fakeweb.clean_registry&lt;/code&gt; para que cada especificaci&amp;oacute;n comience en el mismo estado.&lt;/p&gt;

&lt;p&gt;En la especificaci&amp;oacute;n de &lt;code&gt;WebRequest&lt;/code&gt; escribiremos un test que comprueba que se recupera el tama&amp;ntilde;o del contenido.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/models/web_request_spec.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require &amp;#x27;spec_helper&amp;#x27;

describe WebRequest do
  it &amp;quot;fetches the content length&amp;quot; do
    FakeWeb.register_uri(:head, &amp;quot;http://example.com&amp;quot;, :content_length =&amp;gt; 123)
    WebRequest.new(:url =&amp;gt; &amp;quot;http://example.com&amp;quot;).content_length.should eq(123)
  end
end&lt;/pre&gt;

&lt;p&gt;Llamamos a &lt;code&gt;Fakeweb.register_uri&lt;/code&gt; para registrar nuestra URL falsa.  El primer argumento del m&amp;eacute;todo recibe el tipo de petici&amp;oacute;n que queremos hacer.  Del archivo nos interesa recuperar su tama&amp;ntilde;o a partir de la informaci&amp;oacute;n del encabezado HTTP, por lo que usamos &lt;code&gt;:head&lt;/code&gt;.  Los otros argumentos son la URL y cualquier otra cabecera que queramos, en este caso s&amp;oacute;lo &lt;code&gt;Content Length&lt;/code&gt;.  Luego creamos un nuevo objeto &lt;code&gt;WebRequest&lt;/code&gt; de nuestra aplicaci&amp;oacute;n que por dentro invocar&amp;aacute; esta URL y comprobamos que el valor devuelto por el m&amp;eacute;todo &lt;code&gt;content_length&lt;/code&gt; es igual al valor establecido en la cabecera.&lt;/p&gt;

&lt;p&gt;Por supuesto, cuando la ejecutamos esta especificaci&amp;oacute;n falla porque nuestro m&amp;eacute;todo &lt;code&gt;content_length&lt;/code&gt; siempre devuelve &lt;code&gt;0&lt;/code&gt;.  Para que pase tenemos que modificar el m&amp;eacute;todo para que devuelta el verdadero valor de tama&amp;ntilde;o del contenido requerido.&lt;/p&gt;


&lt;p class="codeFilePath"&gt;/app/models/web_request.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class WebRequest &amp;lt; ActiveRecord::Base
  def content_length
    uri = URI.parse(url)
    response = Net::HTTP.start(uri.host, uri.port) { |http| http.request_head(uri.path) }
    response[&amp;quot;content-length&amp;quot;].to_i
  end
end&lt;/pre&gt;

&lt;p&gt;Ahora el m&amp;eacute;todo invoca a &lt;code&gt;Net::HTTP.start&lt;/code&gt; utilizando la URL recibida en el modelo.  El bloque luego recibe llamadas a &lt;code&gt;request_head&lt;/code&gt; para obtener las cabeceras de la URL solicitada.  Por &amp;uacute;ltimo devuelve el valor de la cabecera &lt;code&gt;content-length&lt;/code&gt;.

&lt;p&gt;Por defecto Rails no incluye &lt;code&gt;Net::HTTP&lt;/code&gt; as&amp;iacute; que tenemos que hacer un &lt;code&gt;require&lt;/code&gt; en nuestra aplicaci&amp;oacute;n.  Lo haremos en el fichero &lt;code&gt;application.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/auth.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require File.expand_path(&amp;#x27;../boot&amp;#x27;, __FILE__)

require &amp;#x27;net/http&amp;#x27;
require &amp;#x27;rails/all&amp;#x27;
# resto del archivo&lt;/pre&gt;

&lt;p&gt;Con esto pasar&amp;aacute;n todos nuestros tests y si volvemos a cargar la p&amp;aacute;gina de nuestra petici&amp;oacute;n web se mostrar&amp;aacute; el tama&amp;ntilde;o correcto.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/711/original/E276I04.png" width="800" height="322" alt="The correct file size is now shown."/&gt;
&lt;/div&gt;

&lt;p&gt;Fakeweb es una soluci&amp;oacute;n muy buena para gestionar peticiones a web externas en nuestros tests.&lt;/p&gt;
</description>
      <pubDate>Sat, 13 Aug 2011 20:34:34 +0000</pubDate>
      <guid>http://es.asciicasts.com/episodes/276-tests-dependientes-de-la-hora-y-peticiones-web-externas</guid>
      <link>http://es.asciicasts.com/episodes/276-tests-dependientes-de-la-hora-y-peticiones-web-externas</link>
    </item>
  </channel>
</rss>

