<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
 
 <title>Alex Rothenberg</title>
 
 <link href="http://www.alexrothenberg.com/" rel="alternate" type="text/html" />
 <updated>2011-11-18T07:38:26-08:00</updated>
 <id>http://www.alexrothenberg.com/</id>
 <author>
   <name>Alex Rothenberg</name>
   <email>alex@alexrothenberg.com</email>
 </author>

 
 <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/alexrothenberg" /><feedburner:info uri="alexrothenberg" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
   <title>Programming With Kids</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/_ujDDbYsgxQ/programming-with-kids.html" />
   <published>2011-11-14T00:00:00-08:00</published>
   <updated>2011-11-14T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2011/11/14/programming-with-kids</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve started to teach my kids to program. I figured I build websites professionally and it&amp;#8217;d be a fun way for me to share what I do and help supplement their learning. And it was something they expressed interest in not something I was pushing. I suggested we build our own small version of facebook or twitter. Very quickly I learned two truths&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;websites are boring&lt;/li&gt;

&lt;li&gt;games are fun&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Okay. I&amp;#8217;ve never built a game before after a little digging there are plenty of tools in the open source world and many built on Ruby. We&amp;#8217;re currently experimenting with three different tools/technologies.&lt;/p&gt;

&lt;h2 id='shoes'&gt;Shoes&lt;/h2&gt;

&lt;p&gt;I first came across &lt;a href='http://shoesrb.com/'&gt;Shoes&lt;/a&gt; several years ago and was blown away. It was originally written by &lt;em&gt;why&lt;/em&gt; and is now maintained by Team Shoes &lt;a href='https://github.com/shoes/shoes'&gt;on github&lt;/a&gt;. &amp;#8220;Shoes is the best little DSL for cross-platform GUI programming there is. It feels like real Ruby, rather than just another C++ library wrapper&amp;#8221;&lt;/p&gt;

&lt;p&gt;Writing a Shoes app feels just like writing a Ruby app (it is Ruby!). The best analogy I can use is that what Rails does for websites, Shoes does for GUI apps.&lt;/p&gt;

&lt;p&gt;If you want to create a blue rectangle on a page, here&amp;#8217;s your app&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;Shoes&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;app&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;fill&lt;/span&gt; &lt;span class='n'&gt;blue&lt;/span&gt;
  &lt;span class='n'&gt;rect&lt;/span&gt; &lt;span class='ss'&gt;:top&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;25&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:left&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;50&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:height&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;75&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:width&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;150&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-11-14-programming-with-kids/shoes_a_blue_rectangle.png' alt='A blue rectangle' /&gt;&lt;/p&gt;

&lt;p&gt;We can make it a bit more interactive and allow the user to move our rectangle around with the arrow keys and display the current coordinates&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;Shoes&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;app&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;fill&lt;/span&gt; &lt;span class='n'&gt;blue&lt;/span&gt;
  &lt;span class='vi'&gt;@player&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;rect&lt;/span&gt; &lt;span class='ss'&gt;:top&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;25&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:left&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;50&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:height&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;75&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:width&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;150&lt;/span&gt;
  &lt;span class='vi'&gt;@current_coordinates&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;para&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;(&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;left&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;, &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;top&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;)&amp;quot;&lt;/span&gt;

  &lt;span class='n'&gt;keypress&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;key&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;left&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;key&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='ss'&gt;:right&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;left&lt;/span&gt; &lt;span class='o'&gt;-=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;key&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='ss'&gt;:left&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;top&lt;/span&gt;  &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;key&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='ss'&gt;:down&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;top&lt;/span&gt;  &lt;span class='o'&gt;-=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;key&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='ss'&gt;:up&lt;/span&gt;
    &lt;span class='vi'&gt;@current_coordinates&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;replace&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;(&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;left&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;, &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;top&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;)&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-11-14-programming-with-kids/shoes_the_blue_rectangle_moves.png' alt='The Blue Rectangle Moves' /&gt;&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re not limited to blue rectangles. We can replace it with an image&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;Shoes&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;app&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='vi'&gt;@player&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;image&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;images/Starfighter.png&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:top&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;25&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:left&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;50&lt;/span&gt;
  &lt;span class='vi'&gt;@current_coordinates&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;para&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;(&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;left&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;, &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;top&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;)&amp;quot;&lt;/span&gt;

  &lt;span class='n'&gt;keypress&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;key&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;left&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;key&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='ss'&gt;:right&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;left&lt;/span&gt; &lt;span class='o'&gt;-=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;key&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='ss'&gt;:left&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;top&lt;/span&gt;  &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;key&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='ss'&gt;:down&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;top&lt;/span&gt;  &lt;span class='o'&gt;-=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;key&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='ss'&gt;:up&lt;/span&gt;
    &lt;span class='vi'&gt;@current_coordinates&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;replace&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;(&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;left&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;, &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;top&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;)&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-11-14-programming-with-kids/shoes_starfighter_player.png' alt='The Player is a Starship' /&gt;&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re writing Ruby in a fairly natural way. Shoes just gives us GUI methods like &lt;code&gt;rect&lt;/code&gt; to create a rectangle or &lt;code&gt;para&lt;/code&gt; to create a paragraph. Because this is Ruby, as your Shoes app gets more complex you can create classes and methods to organize and keep it manageable just as you would in any other app.&lt;/p&gt;

&lt;p&gt;There are all sorts of great resources out there including&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://shoesrb.com/manual'&gt;The Shoes Manual&lt;/a&gt; which includes a reference for all &lt;a href='http://shoesrb.com/manual/Elements.html'&gt;the elements&lt;/a&gt; you may use (like rect or para)&lt;/li&gt;

&lt;li&gt;&lt;a href='https://github.com/ashbb/shoes_tutorial_walkthrough/blob/master/README.md'&gt;why&amp;#8217;s tutorial&lt;/a&gt; - the original introduction to Shoes&lt;/li&gt;

&lt;li&gt;&lt;a href='https://github.com/shoes/shoes/tree/develop/samples'&gt;sample apps&lt;/a&gt; - there are some really good ones here!&lt;/li&gt;

&lt;li&gt;&lt;a href='http://teachingkids.railsbridge.org/2009/08/15/teaching-ruby-to-high-school-girls.html'&gt;Teaching Ruby to High School Girls&lt;/a&gt; (using Shoes) article by Sarah Mei&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='gosu'&gt;Gosu&lt;/h2&gt;

&lt;p&gt;&lt;a href='http://libgosu.org/'&gt;Gosu&lt;/a&gt; is a gaming library so while Shoes lets us build any sort of GUI apps this is seemed like it might be a better fit since we&amp;#8217;re interested in gaming. Luckily there&amp;#8217;s a gem that wraps up the Ruby interface (Gosu can be used from C++ or Ruby).&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;gem install gosu&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If we want to build a similar game to what we did in Shoes with a play we move around via the arrow keys we need to subclass the &lt;code&gt;Gosu::Window&lt;/code&gt; class.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;gosu&amp;#39;&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Player&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;window&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@image&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Gosu&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Image&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;window&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;media/Starfighter.png&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kp'&gt;false&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='vi'&gt;@y&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;125&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;50&lt;/span&gt;
    &lt;span class='vi'&gt;@angle&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;draw&lt;/span&gt;
    &lt;span class='vi'&gt;@image&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;draw_rot&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='vi'&gt;@y&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='vi'&gt;@angle&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;GameWindow&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Gosu&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Window&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;
    &lt;span class='k'&gt;super&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;640&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;480&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kp'&gt;false&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;caption&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Gosu Tutorial Game&amp;quot;&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;draw&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;draw&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='n'&gt;window&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;GameWindow&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;
&lt;span class='n'&gt;window&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;show&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And we see a window with a player that looks like a starship&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-11-14-programming-with-kids/gosu_starfighter.png' alt='Starship player' /&gt;&lt;/p&gt;

&lt;p&gt;Its not too hard to make it move by overriding the &lt;code&gt;update&lt;/code&gt; method in our window class&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;gosu&amp;#39;&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Player&lt;/span&gt;
  &lt;span class='kp'&gt;attr_accessor&lt;/span&gt; &lt;span class='ss'&gt;:x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:y&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;window&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@image&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Gosu&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Image&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;window&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;media/Starfighter.bmp&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kp'&gt;false&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='vi'&gt;@y&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;75&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;50&lt;/span&gt;
    &lt;span class='vi'&gt;@angle&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;draw&lt;/span&gt;
    &lt;span class='vi'&gt;@image&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;draw_rot&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@x&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='vi'&gt;@y&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='vi'&gt;@angle&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;GameWindow&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Gosu&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Window&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;
    &lt;span class='k'&gt;super&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;400&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;300&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kp'&gt;false&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;caption&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Our Game&amp;quot;&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@current_coordinates&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Gosu&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Font&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='no'&gt;Gosu&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='n'&gt;default_font_name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;20&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;update&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt; &lt;span class='o'&gt;-=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;button_down?&lt;/span&gt; &lt;span class='no'&gt;Gosu&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;KbLeft&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;button_down?&lt;/span&gt; &lt;span class='no'&gt;Gosu&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;KbRight&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;y&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;button_down?&lt;/span&gt; &lt;span class='no'&gt;Gosu&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;KbDown&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;y&lt;/span&gt; &lt;span class='o'&gt;-=&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='n'&gt;button_down?&lt;/span&gt; &lt;span class='no'&gt;Gosu&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;KbUp&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;draw&lt;/span&gt;
    &lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;draw&lt;/span&gt;
    &lt;span class='vi'&gt;@current_coordinates&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;draw&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;(&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;x&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;, &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@player&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;y&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;)&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mh'&gt;0xffffff00&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='n'&gt;window&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;GameWindow&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;
&lt;span class='n'&gt;window&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;show&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-11-14-programming-with-kids/gosu_starfighter_moves.png' alt='Starship player moves' /&gt;&lt;/p&gt;

&lt;p&gt;This example can be extended into a full Asteroids like like game where your ship has inertia. You should look at the &lt;a href='https://github.com/jlnr/gosu/blob/master/examples/Tutorial.rb'&gt;source&lt;/a&gt; or an &lt;a href='https://github.com/jlnr/gosu/wiki/Ruby-Tutorial'&gt;explanation&lt;/a&gt; on the gosu site.&lt;/p&gt;

&lt;p&gt;There are all sorts of great resources out there including&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Samples from the &lt;a href='http://www.libgosu.org/cgi-bin/mwf/board_show.pl?bid=2'&gt;Gosu Showcase&lt;/a&gt; or &lt;table&gt;
&lt;tr&gt;
  &lt;td style='text-align: center;'&gt;&lt;a href='https://github.com/PhilCK/Falling-Blocks'&gt;Falling Blocks&lt;/a&gt;             &lt;/td&gt;
  &lt;td style='text-align: center;'&gt; or            &lt;/td&gt;
  &lt;td style='text-align: center;'&gt;&lt;a href='https://github.com/jlnr/gosu/blob/master/examples/CptnRuby.rb'&gt;CptnRuby&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-11-14-programming-with-kids/falling_blocks.png' alt='Falling Blocks (tetris)' /&gt;&lt;/td&gt;
  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
  &lt;td&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-11-14-programming-with-kids/cptn_ruby.png' alt='Captain Ruby' /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='https://github.com/ippa/chingu'&gt;Chingu&lt;/a&gt; an extension that seems to let us avoid re-writing common tasks &lt;img src='http://www.alexrothenberg.com/images/2011-11-14-programming-with-kids/robot.png' alt='Robot' /&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='https://github.com/beoran/chipmunk'&gt;Chipmunk&lt;/a&gt; a physics library that makes it easy to do things like collision detection, gravity, etc &lt;img src='http://www.alexrothenberg.com/images/2011-11-14-programming-with-kids/gosu_chipmunk.png' alt='Gravity and Collisions demo' /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though we&amp;#8217;re still writing Ruby, Gosu feels more like C++ Windows development I used to do long long time ago. I&amp;#8217;m not sure if that&amp;#8217;s inevitable and need to keep using Gosu to find out.&lt;/p&gt;

&lt;h2 id='gamesalad'&gt;gamesalad&lt;/h2&gt;

&lt;p&gt;The last framework we&amp;#8217;ve been working with is pretty different. &lt;a href='http://gamesalad.com/'&gt;GameSalad&lt;/a&gt; advertises it lets you &amp;#8220;Create games for iPhone, iPad, Android, Mac, and HTML5. No coding required.&amp;#8221;&lt;/p&gt;

&lt;p&gt;It follows a model similar to what Adobe Flash uses where you have &lt;code&gt;Scenes&lt;/code&gt; containing &lt;code&gt;Actors&lt;/code&gt;. You write your programs in a visual editor by dragging and dropping Actors onto Scenes, Rules onto Actors and Behavior onto Rules. For instance if we have a starship actor and we drop these rules onto it&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-11-14-programming-with-kids/gamesalad_starfighter_movement_rules.png' alt='Starfighter rules' /&gt;&lt;/p&gt;

&lt;p&gt;We will get our familiar spaceship that can move left and right&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-11-14-programming-with-kids/gamesalad_starfighter_movement.png' alt='Starfighter Moving' /&gt;&lt;/p&gt;

&lt;p&gt;GameSalad is the least familiar to me but seems to be easiest for my kids to start working on. Not having to write any &amp;#8220;code&amp;#8221; or &amp;#8220;do programming&amp;#8221; makes it much easier to get started. It also can create iPhone or iPad games and I would never dream of exposing my kids to Objective-C.&lt;/p&gt;

&lt;h2 id='whats_next'&gt;What&amp;#8217;s next?&lt;/h2&gt;

&lt;p&gt;We&amp;#8217;ve started experimenting with all three of these tools and so far are having fun with all three. Hopefully we&amp;#8217;ll figure out what works for us and perhaps try to write about it again in a few months.&lt;/p&gt;

&lt;p&gt;After writing this I came across a recent NY Times article &lt;a href='http://www.nytimes.com/2011/11/10/technology/personaltech/computer-programming-for-children-minus-cryptic-syntax.html'&gt;Programming for Children, Minus Cryptic Syntax&lt;/a&gt; and &lt;a href='http://scratch.mit.edu/'&gt;Scratch&lt;/a&gt; also sounds interesting so I may have to look into that sometime too.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/_ujDDbYsgxQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/11/14/programming-with-kids.html</feedburner:origLink></entry>
 
 <entry>
   <title>Twitter is the new RSS Reader</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/TLwbmL47SXI/twitter-is-the-new-rss-reader.html" />
   <published>2011-11-07T00:00:00-08:00</published>
   <updated>2011-11-07T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2011/11/07/twitter-is-the-new-rss-reader</id>
   <content type="html">&lt;p&gt;In 2008 I thought RSS was an awesome way to stay abreast of what&amp;#8217;s going on, but now its 2011 and I find myself using Twitter more often than Google Reader to find new and interesting articles people have written. Readers tweet and retweet articles they find interesting which seems a lower barrier than leaving an &amp;#8220;I like this&amp;#8221; comment. As an author Twitter also gives you some idea of who is reading your posts and a way to connect with them.&lt;/p&gt;

&lt;p&gt;Back in 2008 I created a blog aggregator site &lt;a href='http://waywework.it'&gt;http://waywework.it&lt;/a&gt; to group the all the people I work with and promote others to share their thoughts. I was so excited I even wrote &lt;a href='http://www.alexrothenberg.com/2008/11/09/blog-aggregator-wayweworkit.html'&gt;an article&lt;/a&gt; about it.&lt;/p&gt;

&lt;p&gt;Now that its 2011, I&amp;#8217;ve been asking myself how could I update &lt;a href='http://waywework.it'&gt;http://waywework.it&lt;/a&gt; for the twitter world of today?&lt;/p&gt;

&lt;p&gt;I decide that if we&amp;#8217;re going to follow people on twitter that&amp;#8217;s what my site should facilitate. When new posts come in it should tweet them letting you see them if you follow &lt;a href='https://twitter.com/#!/WayWeWorkIT'&gt;@WayWeWorkIT&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id='enabling_api_access_to_twitter'&gt;Enabling API access to twitter&lt;/h2&gt;

&lt;p&gt;Once I had this I added the &lt;a href='https://github.com/jnunemaker/twitter'&gt;twitter gem&lt;/a&gt; to my application. I have to give a shout out John Nunemaker for writing this fantastic gem which made my task so simple.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Gemfile&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;twitter&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I created a new twitter account &lt;a href='http://twitter.com/WayWeWorkIT'&gt;@WayWeWorkIT&lt;/a&gt; and registered an application at &lt;a href='https://dev.twitter.com/apps'&gt;https://dev.twitter.com/apps&lt;/a&gt; so I had my OAuth and access tokens.&lt;/p&gt;

&lt;p&gt;The only trick was I had to go &lt;code&gt;Application Settings&lt;/code&gt; tab and configure it for &lt;code&gt;Read and Write&lt;/code&gt; access then regenerate the tokens.&lt;/p&gt;

&lt;p&gt;Now that I had the keys and tokens from twitter I had to tell my application to use them without hardcoding them in my code. This took two steps. First, configuring the app to read the tokens from the environment in &lt;code&gt;config/initializers/twitter.rb&lt;/code&gt;. Yes I am somewhat paranoid about accidentally tweeting from development but that &lt;code&gt;if Rails.env.production?&lt;/code&gt; should save me.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;production?&lt;/span&gt;
  &lt;span class='no'&gt;Twitter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;configure&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;consumer_key&lt;/span&gt;       &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;ENV&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;TWITTER_CONSUMER_KEY&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
    &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;consumer_secret&lt;/span&gt;    &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;ENV&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;TWITTER_CONSUMER_SECRET&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
    &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;oauth_token&lt;/span&gt;        &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;ENV&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;TWITTER_OAUTH_TOKEN&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
    &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;oauth_token_secret&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;ENV&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;TWITTER_OAUTH_TOKEN_SECRET&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Secondly, setting the tokens on the heroku environment (I typed the real tokens instead of the XXXXXXXX&amp;#8217;s).&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; heroku config:add &lt;span class='nv'&gt;TWITTER_CONSUMER_KEY&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;XXXXXXXX
&lt;span class='gp'&gt;$&lt;/span&gt; heroku config:add &lt;span class='nv'&gt;TWITTER_CONSUMER_SECRET&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;XXXXXXXX
&lt;span class='gp'&gt;$&lt;/span&gt; heroku config:add &lt;span class='nv'&gt;TWITTER_OAUTH_TOKEN&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;XXXXXXXX
&lt;span class='gp'&gt;$&lt;/span&gt; heroku config:add &lt;span class='nv'&gt;TWITTER_OAUTH_TOKEN_SECRET&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;XXXXXXXX
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We can test it out (after deploying with &lt;code&gt;git push heroku&lt;/code&gt;)&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='err'&gt;$&lt;/span&gt; &lt;span class='n'&gt;heroku&lt;/span&gt; &lt;span class='n'&gt;console&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='no'&gt;Twitter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;tweet&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;http://waywework.it aggregates blog articles&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='c1'&gt;# some big object returned&lt;/span&gt;
&lt;span class='o'&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class='no'&gt;Twitter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;user_timeline&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;wayweworkit&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;text&lt;/span&gt;
&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;http://t.co/FCmUQdc3 aggregates blog articles&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Great we just tweeted our first tweet for the world to see.&lt;/p&gt;

&lt;h2 id='updating_wayweworkit_to_tweet_new_posts'&gt;Updating WayWeWork.IT to tweet new posts&lt;/h2&gt;

&lt;p&gt;The app periodically scans the rss feeds it tracks and when it sees a new post it creates it in the app&amp;#8217;s database.&lt;/p&gt;

&lt;p&gt;First we add a twitter_username to each feed we&amp;#8217;re tracking&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;AddTwitterUsernameToFeeds&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ActiveRecord&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Migration&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;change&lt;/span&gt;
    &lt;span class='n'&gt;add_column&lt;/span&gt; &lt;span class='ss'&gt;:feeds&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:twitter_username&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:string&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then, add an &lt;code&gt;after_create&lt;/code&gt; callback to tweet each time we create a new post.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Post&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ActiveRecord&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;
  &lt;span class='n'&gt;after_create&lt;/span&gt; &lt;span class='ss'&gt;:tweet&lt;/span&gt;

  &lt;span class='n'&gt;delegate&lt;/span&gt; &lt;span class='ss'&gt;:twitter_username&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:to&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:feed&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;twitter_username_with_at_sign&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;@&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;feed_twitter_username&lt;/span&gt; &lt;span class='o'&gt;||&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;WayWeWorkIT&amp;#39;&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2' /&gt;
&lt;span class='s2'&gt;  end&lt;/span&gt;

&lt;span class='s2'&gt;  # See https://dev.twitter.com/docs/tco-link-wrapper/faq#Will_t.co-wrapped_links_always_be_the_same_length&lt;/span&gt;
&lt;span class='s2'&gt;  # We should query instead of hardcoding 20&lt;/span&gt;
&lt;span class='s2'&gt;  def short_url_length&lt;/span&gt;
&lt;span class='s2'&gt;    20&lt;/span&gt;
&lt;span class='s2'&gt;  end&lt;/span&gt;

&lt;span class='s2'&gt;  def tweet&lt;/span&gt;
&lt;span class='s2'&gt;    if Rails.env.production?&lt;/span&gt;
&lt;span class='s2'&gt;      non_title_part_of_tweet = &amp;quot;&lt;/span&gt; &lt;span class='c1'&gt;#{&amp;#39;x&amp;#39;*short_url_length} via #{twitter_username_with_at_sign}&amp;quot;&lt;/span&gt;
      &lt;span class='n'&gt;max_title_length&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;140&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt; &lt;span class='n'&gt;non_title_part_of_tweet&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;length&lt;/span&gt;

      &lt;span class='n'&gt;tweet&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;title&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;truncate&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;max_title_length&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;url&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; via &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;twitter_username_with_at_sign&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;
      &lt;span class='no'&gt;Twitter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;update&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;tweet&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Again with the &amp;#8220;if Rails.env.production?&amp;#8221; paranoia? You do know that you can never be too paranoid :)&lt;/p&gt;

&lt;p&gt;With the twitter gem its one line to tweet &lt;code&gt;Twitter.update(tweet)&lt;/code&gt;. The rest of it is to shorten the title so twitter&amp;#8217;s 140 character limit wont cut off the url or the author&amp;#8217;s name.&lt;/p&gt;

&lt;p&gt;Once this is in we&amp;#8217;ll start seeing tweets like&lt;/p&gt;

&lt;p&gt;&lt;a href='https://twitter.com/#!/WayWeWorkIT/status/131380463301427200'&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-11-07-twitter-is-the-new-rss-reader/using_bdd_and_email_spec_gem.png' alt='Using BDD and the email_spec gem to implement Email www.alexrothenberg.com/2011/10/31/usi… via @alexrothenberg' /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href='https://twitter.com/#!/WayWeWorkIT/status/133556175563259904'&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-11-07-twitter-is-the-new-rss-reader/twitter_is_the_new_rss_reader.png' alt='Twitter is the new RSS Reader http://www.alexrothenberg.com/2011/11/07/twitter-is-the-new-rss-reader.html via @alexrothenberg' /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go ahead and follow &lt;a href='https://twitter.com/#!/WayWeWorkIT'&gt;@WayWeWorkIT&lt;/a&gt; on twitter and you&amp;#8217;ll start seeing these blog posts.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/TLwbmL47SXI" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/11/07/twitter-is-the-new-rss-reader.html</feedburner:origLink></entry>
 
 <entry>
   <title>Using BDD and the email_spec gem to implement Email</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/POsBy-q5hd0/using-bdd-and-the-email_spec-gem-to-implement-email.html" />
   <published>2011-10-31T00:00:00-07:00</published>
   <updated>2011-10-31T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2011/10/31/using-bdd-and-the-email_spec-gem-to-implement-email</id>
   <content type="html">&lt;p&gt;When implementing email functionality, the &lt;a href='https://github.com/bmabey/email-spec'&gt;email_spec gem&lt;/a&gt; is something I&amp;#8217;ve decided I can&amp;#8217;t live without. It makes it so easy to write RSpec specs and Cucumber features around your email that you have no excuse not to. Today I&amp;#8217;m going to go through an example how I recently used BDD to send an email in an app I was working on.&lt;/p&gt;

&lt;p&gt;When I think about email and my Rails environments this is how I typically want them to behave.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;test&lt;/strong&gt; should not send emails and allow us to write specs or features against them&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;development&lt;/strong&gt; should not send emails but provide a UI to view what would be sent on localhost&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;staging&lt;/strong&gt; should not send emails but provide a UI to view what would be sent on a server&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;production&lt;/strong&gt; should send real emails to real people&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last week I wrote about &lt;a href='http://www.alexrothenberg.com/2011/10/24/using-letter-opener-to-view-sent-email-on-a-server.html'&gt;using letter opener to View Sent Email on a Server (without actually sending anything)&lt;/a&gt; describing how the &lt;code&gt;letter_opener gem&lt;/code&gt; helps us in the &lt;em&gt;development&lt;/em&gt; and &lt;em&gt;staging&lt;/em&gt; environments. This article focuses on using &lt;code&gt;email_spec gem&lt;/code&gt; in the &lt;em&gt;test&lt;/em&gt; environment.&lt;/p&gt;

&lt;h2 id='our_sample_project'&gt;Our Sample Project&lt;/h2&gt;

&lt;p&gt;Let&amp;#8217;s imagine we are working on a new startup in stealth mode. We want to generate buzz and prepare for a beta launch. We&amp;#8217;re hiding the fact its all vaporware with a splashy homepage where people can request an invitation to the beta and records their email in our database. This is the same example as my article last week and there&amp;#8217;s a live demo at &lt;a href='http://awesome-site-staging.heroku.com/'&gt;http://awesome-site-staging.heroku.com/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What we&amp;#8217;ll do today is not just record the email address but also send a &amp;#8220;thanks for your interest&amp;#8221; email to the user. We&amp;#8217;re going to do this in BDD fashion bouncing back and forth between &lt;code&gt;Cucumber Scenarios&lt;/code&gt; and &lt;code&gt;RSpec Unit Tests&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Writing a cucumber scenario&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;While the scenario fails&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write a failing rspec spec&lt;/li&gt;

&lt;li&gt;Write code to make it pass&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Cucumber scenario tells us what should be accomplished and when it fails it we use that to tell us what unit test we should write.&lt;/p&gt;

&lt;h2 id='adding_the_email_spec_gem'&gt;Adding the &lt;em&gt;email_spec&lt;/em&gt; gem&lt;/h2&gt;

&lt;p&gt;We add it to our &lt;code&gt;Gemfile&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;group&lt;/span&gt; &lt;span class='ss'&gt;:test&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;email_spec&amp;#39;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We bundle and use the email_spec generator to let it initialize itself.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; bundle
&lt;span class='gp'&gt;$&lt;/span&gt; rails g email_spec:steps
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;There&amp;#8217;s also a manual step to get cucumber to load the email_spec gem. We need to create a file &lt;code&gt;features/support/email_spec.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;email_spec/cucumber&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='our_first_cucumber_scenario'&gt;Our first Cucumber Scenario&lt;/h2&gt;

&lt;p&gt;We know that when a user requests an invitation they should get an email so we write that requirement as a Cucumber Scenario. &lt;code&gt;features/request_an_invitation.feature&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='gherkin'&gt;&lt;span class='nc'&gt;Feature:&lt;/span&gt;&lt;span class='no'&gt; Build excitement for this vaporware&lt;/span&gt;&lt;span class='nb' /&gt;
&lt;span class='nb'&gt;  In order to drum up interest&lt;/span&gt;
&lt;span class='nb'&gt;  As a user&lt;/span&gt;
&lt;span class='nb'&gt;  I will receive an exciting email when I request an invitation&lt;/span&gt;

  &lt;span class='nc'&gt;Scenario:&lt;/span&gt;&lt;span class='no'&gt; Someone requests an invitation and receives an email&lt;/span&gt;
&lt;span class='k'&gt;    Given &lt;/span&gt;I am on the home page
     &lt;span class='k'&gt;When &lt;/span&gt;I request an invitation for &lt;span class='s'&gt;&amp;quot;gullible@lemmings.com&amp;quot;&lt;/span&gt;
     &lt;span class='k'&gt;Then &lt;/span&gt;&lt;span class='s'&gt;&amp;quot;gullible@lemmings.com&amp;quot;&lt;/span&gt; should receive 1 email
      &lt;span class='k'&gt;And &lt;/span&gt;they open the email
      &lt;span class='k'&gt;And &lt;/span&gt;they should see the email delivered from &lt;span class='s'&gt;&amp;quot;alex@awesome-startup.com&amp;quot;&lt;/span&gt;
      &lt;span class='k'&gt;And &lt;/span&gt;they should see &lt;span class='s'&gt;&amp;quot;Invitation request for Awesome New Startup received&amp;quot;&lt;/span&gt; in the email subject
      &lt;span class='k'&gt;And &lt;/span&gt;they should see &lt;span class='s'&gt;&amp;quot;Dear gullible@lemmings.com,&amp;quot;&lt;/span&gt; in the email text part body
      &lt;span class='k'&gt;And &lt;/span&gt;they should see &lt;span class='s'&gt;&amp;quot;We have received your request &amp;quot;&lt;/span&gt; in the email text part body
      &lt;span class='k'&gt;And &lt;/span&gt;they should see &lt;span class='s'&gt;&amp;quot;Please check back at http://awesome-site-staging.heroku.com&amp;quot;&lt;/span&gt; in the email text part body
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We run it and it tells us we have a couple of missing steps.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;1 scenario (1 undefined)&lt;/span&gt;
&lt;span class='go'&gt;9 steps (7 skipped, 2 undefined)&lt;/span&gt;
&lt;span class='go'&gt;0m0.006s&lt;/span&gt;

&lt;span class='go'&gt;You can implement step definitions for undefined steps with these snippets:&lt;/span&gt;

&lt;span class='go'&gt;Given /^I am on the home page$/ do&lt;/span&gt;
&lt;span class='go'&gt;  pending # express the regexp above with the code you wish you had&lt;/span&gt;
&lt;span class='go'&gt;end&lt;/span&gt;

&lt;span class='go'&gt;When /^I request an invitation for &amp;quot;([^&amp;quot;]*)&amp;quot;$/ do |arg1|&lt;/span&gt;
&lt;span class='go'&gt;  pending # express the regexp above with the code you wish you had&lt;/span&gt;
&lt;span class='go'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Oh right, &lt;a href='http://aslakhellesoy.com/post/11055981222/the-training-wheels-came-off'&gt;the training wheels came off&lt;/a&gt; in &lt;code&gt;cucumber-rails v1.1.1&lt;/code&gt; and we don&amp;#8217;t have &lt;code&gt;web_steps.rb&lt;/code&gt; anymore. Let&amp;#8217;s write these steps using &lt;em&gt;capybara&lt;/em&gt; in &lt;code&gt;features/step_definitions/invite_steps.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;Given&lt;/span&gt;&lt;span class='sr'&gt; /^I am on the home page$/&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;visit&lt;/span&gt; &lt;span class='n'&gt;root_path&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='no'&gt;When&lt;/span&gt;&lt;span class='sr'&gt; /^I request an invitation for &amp;quot;([^&amp;quot;]*)&amp;quot;$/&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;email&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='n'&gt;visit&lt;/span&gt; &lt;span class='n'&gt;root_path&lt;/span&gt;
  &lt;span class='n'&gt;fill_in&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;email&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:with&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;email&lt;/span&gt;
  &lt;span class='n'&gt;click_button&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Request Invitation&amp;#39;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We run one more time and get a failure we expect. Its telling us we haven&amp;#8217;t written any code to implement the scenario yet!&lt;/p&gt;

&lt;p&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;  Then &amp;quot;gullible@lemmings.com&amp;quot; should receive 1 email&lt;/span&gt;
&lt;span class='go'&gt;  expected: 1&lt;/span&gt;
&lt;span class='go'&gt;       got: 0 (using ==) (RSpec::Expectations::ExpectationNotMetError)&lt;/span&gt;
&lt;span class='go'&gt;  ./features/step_definitions/email_steps.rb:52:in `/^(?:I|they|&amp;quot;([^&amp;quot;]*?)&amp;quot;) should receive (an|no|\d+) emails?$/&amp;#39;&lt;/span&gt;
&lt;span class='go'&gt;  features/request_an_invitation.feature:9:in `Then &amp;quot;gullible@lemmings.com&amp;quot; should receive 1 email&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/p&gt;

&lt;h2 id='dropping_into_rspec_unit_tests'&gt;Dropping into RSpec unit tests&lt;/h2&gt;

&lt;p&gt;Our failing feature tells us what we need to implement so we drop down to the unit test level and start implementing it with TDD. The feature tells us an email should be be generated so let&amp;#8217;s go. We&amp;#8217;ll add to our &lt;code&gt;invites_controller_spec&lt;/code&gt; specifying that it should create and deliver an &lt;code&gt;InviteMailer&lt;/code&gt;. &lt;code&gt;spec/controllers/invites_controller_spec.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;spec_helper&amp;#39;&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;InvitesController&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;PUT #update&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;let&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:invite&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;mock&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:email&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;someone@someco.com&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:save&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='kp'&gt;true&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='n'&gt;let&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:invite_mailer&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;mock&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='no'&gt;InviteMailer&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should_receive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:invite_requested&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;with&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;invite&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;and_return&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;invite_mailer&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='n'&gt;invite_mailer&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should_receive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:deliver&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='no'&gt;Invite&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should_receive&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:new&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;with&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;email&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;someone@someco.com&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;and_return&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;invite&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='ss'&gt;:create&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:invite&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='ss'&gt;:email&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;someone@someco.com&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;redirect_to&lt;/span&gt; &lt;span class='n'&gt;root_url&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;set_the_flash&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;Thanks for your interest someone@someco.com.  You will hear from us soon.&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Of course we get an error &lt;code&gt;uninitialized constant InviteMailer&lt;/code&gt;. We fix that by creating the mailer (it doesn&amp;#8217;t do anything yet) &lt;code&gt;app/mailers/invite_mailer.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;InviteMailer&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ActionMailer&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The error changes&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;Failure/Error: InviteMailer.should_receive(:invite_requested).with(invite).and_return(invite_mailer)&lt;/span&gt;
&lt;span class='go'&gt;  (&amp;lt;InviteMailer (class)&amp;gt;).invite_requested(#&amp;lt;RSpec::Mocks::Mock:0x82c96210 @name=nil&amp;gt;)&lt;/span&gt;
&lt;span class='go'&gt;      expected: 1 time&lt;/span&gt;
&lt;span class='go'&gt;      received: 0 times&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We add the code to our controller to create and deliver the email in &lt;code&gt;app/controllers/invites_controller.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;InvitesController&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ApplicationController&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;create&lt;/span&gt;
    &lt;span class='vi'&gt;@invite&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Invite&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:invite&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='vi'&gt;@invite&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;save&lt;/span&gt;
      &lt;span class='no'&gt;InviteMailer&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;invite_requested&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@invite&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;deliver&lt;/span&gt;
      &lt;span class='n'&gt;redirect_to&lt;/span&gt; &lt;span class='n'&gt;root_path&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:notice&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Thanks for your interest &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@invite&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;email&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;.  You will hear from us soon.&amp;quot;&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt;
      &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:action&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;new&amp;quot;&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Are we done?&lt;/p&gt;

&lt;h2 id='checking_the_cucumber_scenario'&gt;Checking the Cucumber Scenario&amp;#8230;&lt;/h2&gt;

&lt;p&gt;The RSpec unit tests pass now but the Cucumber features are still failing.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;When I request an invitation for &amp;quot;gullible@lemmings.com&amp;quot;            # features/step_definitions/invite_steps.rb:5&lt;/span&gt;
&lt;span class='go'&gt;  undefined method `invite_requested&amp;#39; for InviteMailer:Class (NoMethodError)&lt;/span&gt;
&lt;span class='go'&gt;  ./app/controllers/invites_controller.rb:10:in `create&amp;#39;&lt;/span&gt;
&lt;span class='go'&gt;  (eval):2:in `send&amp;#39;&lt;/span&gt;
&lt;span class='go'&gt;  (eval):2:in `click_button&amp;#39;&lt;/span&gt;
&lt;span class='go'&gt;  ./features/step_definitions/invite_steps.rb:8:in `/^I request an invitation for &amp;quot;([^&amp;quot;]*)&amp;quot;$/&amp;#39;&lt;/span&gt;
&lt;span class='go'&gt;  features/request_an_invitation.feature:8:in `When I request an invitation for &amp;quot;gullible@lemmings.com&amp;quot;&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Duh our &lt;code&gt;InviteMailer&lt;/code&gt; doesn&amp;#8217;t do anything.&lt;/p&gt;

&lt;h2 id='back_down_to_the_unit_tests'&gt;Back down to the unit tests&lt;/h2&gt;

&lt;p&gt;We write our &lt;code&gt;spec/mailers/invite_mailer_spec.rb&lt;/code&gt;. We need to include some &lt;em&gt;EmailSpec&lt;/em&gt; modules so we have access to its matchers.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;spec_helper&amp;#39;&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;InviteMailer&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='kp'&gt;include&lt;/span&gt; &lt;span class='no'&gt;EmailSpec&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Helpers&lt;/span&gt;
  &lt;span class='kp'&gt;include&lt;/span&gt; &lt;span class='no'&gt;EmailSpec&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Matchers&lt;/span&gt;

  &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;.invite_requested&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;let&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:invite&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='no'&gt;Factory&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;build&lt;/span&gt; &lt;span class='ss'&gt;:invite&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:email&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;someone@someco.com&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;one email to one user&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;subject&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='no'&gt;InviteMailer&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;invite_requested&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;invite&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;deliver_to&lt;/span&gt;     &lt;span class='n'&gt;invite&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;email&lt;/span&gt;                                                  &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;deliver_from&lt;/span&gt;   &lt;span class='s1'&gt;&amp;#39;alex@awesome-startup.com&amp;#39;&lt;/span&gt;                                    &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have_subject&lt;/span&gt;   &lt;span class='s2'&gt;&amp;quot;Invitation request for Awesome New Startup received&amp;quot;&lt;/span&gt;         &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have_body_text&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Dear someone@someco.com,&amp;quot;&lt;/span&gt;                                    &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have_body_text&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;We have received your request&amp;quot;&lt;/span&gt;                               &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have_body_text&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Please check back at http://awesome-site-staging.heroku.com&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Of course it fails because we still haven&amp;#8217;t implemented anything. Let&amp;#8217;s add some code to &lt;code&gt;app/mailers/invite_mailer.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;InviteMailer&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ActionMailer&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;invite_requested&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;invite&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@invite&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;invite&lt;/span&gt;
    &lt;span class='n'&gt;mail&lt;/span&gt; &lt;span class='ss'&gt;:to&lt;/span&gt;      &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;invite&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;email&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
         &lt;span class='ss'&gt;:from&lt;/span&gt;    &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;alex@awesome-startup.com&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
         &lt;span class='ss'&gt;:subject&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Invitation request for Awesome New Startup received&amp;#39;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;and we can use haml to format the body in &lt;code&gt;app/views/invite_mailer/invite_requested.text.haml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='erb'&gt;&lt;span class='x'&gt;== Dear #{@invite.email},&lt;/span&gt;
&lt;span class='x'&gt;We have received your request to be invited into our awesome site. We&amp;#39;ll let you know as soon as its available.&lt;/span&gt;
&lt;span class='x'&gt;Please check back at http://awesome-site-staging.heroku.com&lt;/span&gt;
&lt;span class='x'&gt;You must be very excited!&lt;/span&gt;
&lt;span class='x'&gt;Thanks&lt;/span&gt;
&lt;span class='x'&gt;An Awesome New Startup&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;We run the &lt;code&gt;rake&lt;/code&gt; one more time and &amp;#8230;&lt;/p&gt;

&lt;h2 id='were_done'&gt;We&amp;#8217;re Done&lt;/h2&gt;

&lt;p&gt;Everything passes - the specs &lt;em&gt;and&lt;/em&gt; the features!&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; rake
&lt;span class='go'&gt;ruby -S rspec &amp;lt;a long list of _spec.rb files&amp;gt;&lt;/span&gt;
&lt;span class='go'&gt;............&lt;/span&gt;

&lt;span class='go'&gt;Finished in 2.64 seconds&lt;/span&gt;
&lt;span class='go'&gt;12 examples, 0 failures&lt;/span&gt;

&lt;span class='go'&gt;ruby -S bundle exec cucumber  --profile default&lt;/span&gt;
&lt;span class='go'&gt;Using the default profile...&lt;/span&gt;
&lt;span class='go'&gt;Feature: Build excitement for this vaporware&lt;/span&gt;
&lt;span class='go'&gt;  In order to drum up interest&lt;/span&gt;
&lt;span class='go'&gt;  As a user&lt;/span&gt;
&lt;span class='go'&gt;  I will receive an exciting email&lt;/span&gt;

&lt;span class='go'&gt;  Scenario: Someone requests an invitation and receives an email&lt;/span&gt;
&lt;span class='go'&gt;    Given I am on the home page&lt;/span&gt;
&lt;span class='go'&gt;    When I request an invitation for &amp;quot;gullible@lemmings.com&amp;quot;&lt;/span&gt;
&lt;span class='go'&gt;    Then &amp;quot;gullible@lemmings.com&amp;quot; should receive 1 email&lt;/span&gt;
&lt;span class='go'&gt;    And they open the email&lt;/span&gt;
&lt;span class='go'&gt;    And they should see the email delivered from &amp;quot;alex@awesome-startup.com&amp;quot;&lt;/span&gt;
&lt;span class='go'&gt;    And they should see &amp;quot;Invitation request for Awesome New Startup received&amp;quot; in the email subject&lt;/span&gt;
&lt;span class='go'&gt;    And they should see &amp;quot;Dear gullible@lemmings.com,&amp;quot; in the email body&lt;/span&gt;
&lt;span class='go'&gt;    And they should see &amp;quot;We have received your request&amp;quot; in the email body&lt;/span&gt;
&lt;span class='go'&gt;    And they should see &amp;quot;Please check back at http://awesome-site-staging.heroku.com&amp;quot; in the email body&lt;/span&gt;

&lt;span class='go'&gt;1 scenario (1 passed)&lt;/span&gt;
&lt;span class='go'&gt;9 steps (9 passed)&lt;/span&gt;
&lt;span class='go'&gt;0m0.293s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I hope you&amp;#8217;ll consider using the &lt;code&gt;email_spec gem&lt;/code&gt; and &lt;code&gt;BDD&lt;/code&gt; the next time you have to add email to your app.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/POsBy-q5hd0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/10/31/using-bdd-and-the-email_spec-gem-to-implement-email.html</feedburner:origLink></entry>
 
 <entry>
   <title>Using Letter Opener to View Sent Email on a Server (without actually sending anything)</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/6Tz9qfag59o/using-letter-opener-to-view-sent-email-on-a-server.html" />
   <published>2011-10-24T00:00:00-07:00</published>
   <updated>2011-10-24T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2011/10/24/using-letter-opener-to-view-sent-email-on-a-server</id>
   <content type="html">&lt;p&gt;When developing email functionality you don&amp;#8217;t want to send real emails to real people before in production. At the same time you need to send them to ensure they are formatted correctly and contain the proper information. You can (and should) write integration tests to verify this but that helps developers gain confidence, what can we do to show non-technical stakeholders that it all works?&lt;/p&gt;

&lt;p&gt;Today I&amp;#8217;m going to show you how to use Ryan Bates&amp;#8217; &lt;a href='https://github.com/ryanb/letter_opener'&gt;letter_opener&lt;/a&gt; gem to let you preview your emails without actually sending them. Ryan of course does the always awesome &lt;a href='http://railscasts.com'&gt;RailsCasts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s think about the different Rails environments and how we want them to behave with email.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;test&lt;/strong&gt; should not send emails and allow us to write specs or features against them&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;development&lt;/strong&gt; should not send emails but provide a UI to view what would be sent&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;staging&lt;/strong&gt; should not send emails but provide a UI to view what would be sent&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;production&lt;/strong&gt; should send real emails to real people&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Looking at this, Rails works really well for &lt;em&gt;test&lt;/em&gt; with ActionMailer&amp;#8217;s :test delivery method that stores the emails in the ActionMailer::Base.deliveries array so you can then use &lt;a href='https://github.com/bmabey/email-spec'&gt;email_spec&lt;/a&gt; to write your specs. &lt;em&gt;Production&lt;/em&gt; is also covered as long as you give it your mail server configuration. That leaves &lt;em&gt;development&lt;/em&gt; and &lt;em&gt;staging&lt;/em&gt; which look identical but we&amp;#8217;ll see that they are slightly different. I&amp;#8217;ll spend the rest of this article talking about how &lt;em&gt;letter_opener&lt;/em&gt; lets us do what we want in these environments.&lt;/p&gt;

&lt;h2 id='an_example'&gt;An example&lt;/h2&gt;

&lt;p&gt;Let&amp;#8217;s imagine we are working on a new startup in stealth mode. We want to generate buzz and prepare for a beta launch. We&amp;#8217;re hiding the fact its all vaporware with a splashy homepage where people can request an invitation to the beta and it sends a &amp;#8220;thanks for your interest&amp;#8221; email. Lastly, we want to test it in &lt;em&gt;development&lt;/em&gt; and &lt;em&gt;staging&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s a &lt;a href='http://awesome-site-staging.heroku.com/'&gt;live demo at http://awesome-site-staging.heroku.com/&lt;/a&gt; if you want to dive in and start clicking.&lt;/p&gt;

&lt;p&gt;After you request an invitation it shows a page like this&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-10-24-previewing-email-instead-of-sending-prior-to-production/home_page.png' alt='Vaporware Homepage' /&gt;&lt;/p&gt;

&lt;h2 id='logfile_testing_we_can_do_better'&gt;Logfile testing (we can do better)&lt;/h2&gt;

&lt;p&gt;When you fill in your email and click the &lt;code&gt;Request Invitation&lt;/code&gt; button, our controller uses a mailer to create and deliver the email.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;InvitesController&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ApplicationController&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;create&lt;/span&gt;
    &lt;span class='vi'&gt;@invite&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Invite&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:invite&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@invite&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;save&lt;/span&gt;
    &lt;span class='no'&gt;InviteMailer&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;invite_requested&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@invite&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;deliver&lt;/span&gt;
    &lt;span class='n'&gt;redirect_to&lt;/span&gt; &lt;span class='n'&gt;root_path&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:notice&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Thanks for your interest &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@invite&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;email&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;.  You will hear from us soon.&amp;quot;&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The only way to tell whether the email worked is to scroll through the development.log until you see something like this&lt;/p&gt;

&lt;p&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;Sent mail to alex@alexrothenberg.com (20ms)&lt;/span&gt;
&lt;span class='go'&gt;Date: Fri, 21 Oct 2011 15:09:16 -0400&lt;/span&gt;
&lt;span class='go'&gt;From: admin@newstartup.com&lt;/span&gt;
&lt;span class='go'&gt;To: alex@alexrothenberg.com&lt;/span&gt;
&lt;span class='go'&gt;Message-ID: &amp;lt;4ea1c35cc3d5b_6693830916bc43754@Alex-Rothenbergs-MacBook-Pro.local.mail&amp;gt;&lt;/span&gt;
&lt;span class='go'&gt;Subject: Invite requested&lt;/span&gt;
&lt;span class='go'&gt;...&lt;/span&gt;
&lt;span class='go'&gt;We have received your request to be invited into our awesome site. We&amp;#39;ll let you know as soon as its available.&lt;/span&gt;
&lt;span class='go'&gt;Please check back at http://awesome-site.heroku.com&lt;/span&gt;
&lt;span class='go'&gt;You must be very excited!&lt;/span&gt;
&lt;span class='go'&gt;Thanks&lt;/span&gt;
&lt;span class='go'&gt;An Awesome New Startup&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Ok if you&amp;#8217;re a developer and you enjoy reading log files but &lt;em&gt;letter_opener&lt;/em&gt; lets us do better.&lt;/p&gt;

&lt;h2 id='using_letter_opener_in_development'&gt;Using &lt;em&gt;letter_opener&lt;/em&gt; in development&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Letter_opener&lt;/em&gt; provides us with a UI so we can view the emails right in our browser. It&amp;#8217;s super easy to add this gem and I&amp;#8217;ll just copy the instructions from its &lt;a href='https://github.com/ryanb/letter_opener/blob/master/README.rdoc'&gt;README&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Preview email in the browser instead of sending it. This means you do not need to set up email delivery in your development environment, and you no longer need to worry about accidentally sending a test email to someone else’s address&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rails Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First add the gem to your development environment and run the bundle command to install it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gem &amp;quot;letter_opener&amp;quot;, :group =&amp;gt; :development&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then set the delivery method in config/environments/development.rb&lt;/p&gt;

&lt;p&gt;&lt;code&gt;config.action_mailer.delivery_method = :letter_opener&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now any email will pop up in your browser instead of being sent. The messages are stored in tmp/letter_opener.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once we&amp;#8217;ve done that what happens when we use the site to request an invitation? A new tab opens up with the email right there. Now as a user we can tell it&amp;#8217;s correct and any non-technical people on the team can feel their confidence rise.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-10-24-previewing-email-instead-of-sending-prior-to-production/development_letter_opener.png' alt='Previewing an Email with Letter Opener in Development' /&gt;&lt;/p&gt;

&lt;h3 id='how_does_letter_opener_actually_work'&gt;How does letter_opener actually work?&lt;/h3&gt;

&lt;p&gt;Rails goes through the standard flow to create the mail object and when it&amp;#8217;s ready to deliver the message it calls letter_opener&amp;#8217;s &lt;code&gt;deliver!&lt;/code&gt; method because we registered letter_opener as the &lt;em&gt;action_mailer.delivery_method&lt;/em&gt;. Letter_opener saves the email to your file system as an html file then uses &lt;a href='https://github.com/copiousfreetime/launchy'&gt;launchy&lt;/a&gt; to open it in a browser using the file:// protocol.&lt;/p&gt;

&lt;p&gt;There will be a couple of problems once we move onto a server which brings us to &lt;em&gt;staging&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id='using_letter_opener_on_staging'&gt;Using &lt;em&gt;letter_opener&lt;/em&gt; on staging&lt;/h2&gt;

&lt;p&gt;If you&amp;#8217;re like me you probably have a staging environment where you or your stakeholders can validate your app before releasing it to production and your end users. There are two aspects of this environment that wont work with letter_opener the way it did in development&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We need to use http:// not file:// to preview the emails because the browser is not on the same file system where the emails are written&lt;/li&gt;

&lt;li&gt;We may not be able to write to the file system. For example if we have deployed to heroku.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had to make some changes to &lt;em&gt;letter_opener&lt;/em&gt; to support this kind of server environment. The fork is available at &lt;a href='https://github.com/alexrothenberg/letter_opener/tree/on_a_server'&gt;https://github.com/alexrothenberg/letter_opener/tree/on_a_server&lt;/a&gt; and I&amp;#8217;ll update the article if my pull requests are merged back in.&lt;/p&gt;

&lt;p&gt;We need to make a few changes to our application.&lt;/p&gt;

&lt;p&gt;1 - Update our &lt;code&gt;Gemfile&lt;/code&gt; to use the fork from github&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;letter_opener&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;  &lt;span class='ss'&gt;:git&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;git://github.com/alexrothenberg/letter_opener.git&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:branch&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;on_a_server&amp;quot;&lt;/span&gt;
  
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;2 - Add a debugging UI link so users can get to the &amp;#8220;preview emails&amp;#8221; page in something like &lt;code&gt;layouts/application.html.haml&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;link_to&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Preview Emails&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;letter_opener_letters_path&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;staging?&lt;/span&gt;
  
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;3 - If you cannot write to the filesystem let letter_opener know in your &lt;code&gt;config/environments/staging.rb&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;action_mailer&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;delivery_method&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='ss'&gt;:letter_opener&lt;/span&gt;
  &lt;span class='no'&gt;LetterOpener&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;cannot_write_to_file_system!&lt;/span&gt;
  
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we can see it all in action.&lt;/p&gt;

&lt;p&gt;First, we request an invite.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-10-24-previewing-email-instead-of-sending-prior-to-production/invite_requested_on_server.png' alt='Previewing an Email with Letter Opener in Development' /&gt;&lt;/p&gt;

&lt;p&gt;Then, we click the link &amp;#8220;view the Emails that users would have received&amp;#8221; link at the bottom and see an &amp;#8220;inbox&amp;#8221; of everything the app sent.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-10-24-previewing-email-instead-of-sending-prior-to-production/preview_inbox_on_server.png' alt='Previewing an Email with Letter Opener in Development' /&gt;&lt;/p&gt;

&lt;p&gt;Fincally clicking one message lets us preview it just as we did in devellopment&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-10-24-previewing-email-instead-of-sending-prior-to-production/preview_email_on_server.png' alt='Previewing an Email with Letter Opener in Development' /&gt;&lt;/p&gt;

&lt;p&gt;We are able to run on heroku without writing to the file system by using the &lt;a href='https://github.com/defunkt/fakefs'&gt;FakeFS gem&lt;/a&gt; which simulates the filesystem in memory. FakeFS is designed to be used for testing and one caveat to be aware of is that your old emails will disappear if heroku recycles your dyno due to inactivity.&lt;/p&gt;

&lt;p&gt;I hope you think &lt;em&gt;letter_opener&lt;/em&gt; is useful and give it a try the next time you need to send email. Remember here&amp;#8217;s a &lt;a href='http://awesome-site-staging.heroku.com/'&gt;live demo at http://awesome-site-staging.heroku.com/&lt;/a&gt; of the site we&amp;#8217;ve been talking about here.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/6Tz9qfag59o" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/10/24/using-letter-opener-to-view-sent-email-on-a-server.html</feedburner:origLink></entry>
 
 <entry>
   <title>Chaining ActiveRecord Scopes from Different Models</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/dMDHjDyygzU/chaining-active_record-scopes-from-different-models.html" />
   <published>2011-10-17T00:00:00-07:00</published>
   <updated>2011-10-17T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2011/10/17/chaining-active_record-scopes-from-different-models</id>
   <content type="html">&lt;p&gt;You probably know you can chain ActiveRecord scopes together and it combines it all together into one sql statement, but did you know that you can also use scopes from associated models in your chain?&lt;/p&gt;

&lt;p&gt;Let me show you with an example. Let&amp;#8217;s say we have a discussion site where users can post comments with two simple models:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;User&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ActiveRecord&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;
  &lt;span class='n'&gt;has_many&lt;/span&gt; &lt;span class='ss'&gt;:comments&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Comment&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ActiveRecord&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;
  &lt;span class='n'&gt;belongs_to&lt;/span&gt; &lt;span class='ss'&gt;:user&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We could display a list of all users with &lt;code&gt;User.all&lt;/code&gt; or even display them alphabetically with &lt;code&gt;User.order(:name)&lt;/code&gt; (yes I&amp;#8217;d create a scope if I were doing this for real).&lt;/p&gt;

&lt;p&gt;What if I wanted to display the users sorted so that the ones with the most recent comment was first?&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;includes&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:comments&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;merge&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;Comment&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;order&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;comments.created_at desc&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;There&amp;#8217;s a lot going on there, let&amp;#8217;s break it down.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;User.includes(:comments)&lt;/code&gt; - tells active record to query both the &lt;em&gt;users&lt;/em&gt; and &lt;em&gt;comments&lt;/em&gt; tables&lt;/li&gt;

&lt;li&gt;&lt;code&gt;Comment.order(&amp;#39;comments.created_at desc&amp;#39;)&lt;/code&gt; - sorts the results by the date of the comment (we need to specify the table and column name since created_at is also a column on the &lt;em&gt;users&lt;/em&gt; table)&lt;/li&gt;

&lt;li&gt;&lt;code&gt;merge(Comment.XXX)&lt;/code&gt; - lets us use a scope from the &lt;em&gt;Comment&lt;/em&gt; model even though we&amp;#8217;re dealing with &lt;em&gt;Users&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When ActiveRecord and ActiveRelation take all this and convert it into a sql statement it will join the &lt;em&gt;users&lt;/em&gt; and &lt;em&gt;comments&lt;/em&gt; tables and order by the comments.created_at column. Here&amp;#8217;s the sql I actually get in irb (boy am I glad I didn&amp;#8217;t have to type that sql myself!).&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='o'&gt;&amp;gt;&lt;/span&gt; &lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;includes&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:comments&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;merge&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;Comment&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;order&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;comments.created_at desc&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
  &lt;span class='no'&gt;SQL&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='n'&gt;ms&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;  &lt;span class='no'&gt;SELECT&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;users&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class='no'&gt;AS&lt;/span&gt; &lt;span class='n'&gt;t0_r0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;users&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;name&amp;quot;&lt;/span&gt; &lt;span class='no'&gt;AS&lt;/span&gt; &lt;span class='n'&gt;t0_r1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;users&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt; &lt;span class='no'&gt;AS&lt;/span&gt; &lt;span class='n'&gt;t0_r2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                      &lt;span class='s2'&gt;&amp;quot;users&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;updated_at&amp;quot;&lt;/span&gt; &lt;span class='no'&gt;AS&lt;/span&gt; &lt;span class='n'&gt;t0_r3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;comments&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;id&amp;quot;&lt;/span&gt; &lt;span class='no'&gt;AS&lt;/span&gt; &lt;span class='n'&gt;t1_r0&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;comments&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;user_id&amp;quot;&lt;/span&gt; &lt;span class='no'&gt;AS&lt;/span&gt; &lt;span class='n'&gt;t1_r1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                      &lt;span class='s2'&gt;&amp;quot;comments&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;body&amp;quot;&lt;/span&gt; &lt;span class='no'&gt;AS&lt;/span&gt; &lt;span class='n'&gt;t1_r2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;comments&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;created_at&amp;quot;&lt;/span&gt; &lt;span class='no'&gt;AS&lt;/span&gt; &lt;span class='n'&gt;t1_r3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;comments&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;updated_at&amp;quot;&lt;/span&gt; &lt;span class='no'&gt;AS&lt;/span&gt; &lt;span class='n'&gt;t1_r4&lt;/span&gt;
               &lt;span class='no'&gt;FROM&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;users&amp;quot;&lt;/span&gt;
               &lt;span class='no'&gt;LEFT&lt;/span&gt; &lt;span class='no'&gt;OUTER&lt;/span&gt; &lt;span class='no'&gt;JOIN&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;comments&amp;quot;&lt;/span&gt; &lt;span class='no'&gt;ON&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;comments&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;user_id&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;users&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;id&amp;quot;&lt;/span&gt;
               &lt;span class='no'&gt;ORDER&lt;/span&gt; &lt;span class='no'&gt;BY&lt;/span&gt; &lt;span class='n'&gt;comments&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;created_at&lt;/span&gt; &lt;span class='n'&gt;desc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='adding_scopes_to_make_it_usable'&gt;Adding Scopes to make it usable&lt;/h2&gt;

&lt;p&gt;It works to type all that but in a real application you&amp;#8217;d add scopes to make it easier to work with. Let&amp;#8217;s do that!&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;User&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ActiveRecord&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;
  &lt;span class='n'&gt;has_many&lt;/span&gt; &lt;span class='ss'&gt;:comments&lt;/span&gt;
  &lt;span class='n'&gt;scope&lt;/span&gt; &lt;span class='ss'&gt;:by_most_recent_comment&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;includes&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:comments&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;merge&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;Comment&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;most_recent_first&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='n'&gt;scope&lt;/span&gt; &lt;span class='ss'&gt;:with_recent_comments&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;includes&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:comments&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;merge&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;Comment&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;recently&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;month&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;ago&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Comment&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ActiveRecord&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;
  &lt;span class='n'&gt;belongs_to&lt;/span&gt; &lt;span class='ss'&gt;:user&lt;/span&gt;
  &lt;span class='n'&gt;scope&lt;/span&gt; &lt;span class='ss'&gt;:most_recent_first&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;order&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;comments.created_at desc&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='n'&gt;scope&lt;/span&gt; &lt;span class='ss'&gt;:recently&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nb'&gt;lambda&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;date&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;where&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;comments.created_at &amp;gt;= ?&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;date&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we can write some nice simple scopes like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;User.by_most_recent_comment&lt;/code&gt; to get all users sorted so the ones with recent comments are at the top&lt;/li&gt;

&lt;li&gt;&lt;code&gt;User.with_recent_comments&lt;/code&gt; to get all users who have commented in the past month&lt;/li&gt;

&lt;li&gt;&lt;code&gt;User.with_recent_comments.by_most_recent_comment&lt;/code&gt; to get users who have commented in the past month sorted by the date of their most recent comment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy scoping!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/dMDHjDyygzU" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/10/17/chaining-active_record-scopes-from-different-models.html</feedburner:origLink></entry>
 
 <entry>
   <title>Ammeter: The Way to Write Specs for Your Rails Generators</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/3Ftlim7PNSA/ammeter-the-way-to-write-specs-for-your-rails-generators.html" />
   <published>2011-10-10T00:00:00-07:00</published>
   <updated>2011-10-10T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2011/10/10/ammeter-the-way-to-write-specs-for-your-rails-generators</id>
   <content type="html">&lt;img class='heading_image' src='http://www.alexrothenberg.com/images/2011-10-10-ammeter-a-new-gem-write-specs-for-your-rails-generators/ammeter.jpeg' /&gt;
&lt;p&gt;Generators got a complete makeover with Rails 3 making them much easier to write but they&amp;#8217;ve been very hard to test if you&amp;#8217;re using RSpec. That&amp;#8217;s changed now with the &lt;a href='https://github.com/alexrothenberg/ammeter'&gt;Ammeter&lt;/a&gt; &lt;a href='https://rubygems.org/gems/ammeter'&gt;Gem&lt;/a&gt; which lets you write RSpec specs for your generators.&lt;/p&gt;

&lt;h2 id='who_writes_generators'&gt;Who writes generators?&lt;/h2&gt;

&lt;p&gt;Unless you&amp;#8217;ve writing a gem you probably haven&amp;#8217;t created a generator, but I bet you&amp;#8217;re using one someone else created. If you&amp;#8217;ve ever typed&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;rails g rspec:install&amp;#8221; and a &lt;em&gt;spec&lt;/em&gt; director appeared&lt;/li&gt;

&lt;li&gt;&amp;#8220;rails g cucumber:install&amp;#8221; and gotten a &lt;em&gt;features&lt;/em&gt; directory&lt;/li&gt;

&lt;li&gt;&amp;#8220;rails g model post title:string body:text&amp;#8221; and gotten specs for your model&lt;/li&gt;

&lt;li&gt;&amp;#8220;rails g model post title:string body:text&amp;#8221; and gotten mongoid models insead active record ones&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a number of resources for writing generators using &lt;a href='https://github.com/wycats/thor'&gt;thor&lt;/a&gt; including the &lt;a href='http://guides.rubyonrails.org/generators.html#creating-your-first-generator'&gt;generators guide&lt;/a&gt; or &lt;a href='http://asciicasts.com/episodes/218-making-generators-in-rails-3'&gt;railscast #218&lt;/a&gt; and I&amp;#8217;m not going to go into that here. If you&amp;#8217;re using &lt;em&gt;TestUnit&lt;/em&gt;, like the rails core team, you can use &lt;em&gt;Generators::TestCase&lt;/em&gt; which is part of Rails - &lt;a href='https://github.com/plataformatec/devise/tree/master/test/generators'&gt;Devise&lt;/a&gt; has some good examples. For those of us using RSpec we can now use Ammeter.&lt;/p&gt;

&lt;h2 id='writing_specs_with_ammeter'&gt;Writing Specs with Ammeter&lt;/h2&gt;

&lt;p&gt;First you need to tell your gem to use ammeter by 1) adding it to our bundle and 2) making it accessible to our specs.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='c1'&gt;# &amp;lt;YOUR_GEM_NAME&amp;gt;.gemspec&lt;/span&gt;
  &lt;span class='n'&gt;s&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;add_development_dependency&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;ammeter&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='c1'&gt;# spec_helper.rb&lt;/span&gt;
  &lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;ammeter/init&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then we specify the behavior. We&amp;#8217;ll look at an example using Mongoid&amp;#8217;s &lt;a href='https://github.com/mongoid/mongoid/blob/master/lib/rails/generators/mongoid/config/config_generator.rb'&gt;config generator&lt;/a&gt; and its spec &lt;a href='https://github.com/mongoid/mongoid/blob/master/spec/generators/mongoid/config/config_generator_spec.rb'&gt;config_generator_spec&lt;/a&gt;. The generator&amp;#8217;s usage is &lt;code&gt;rails generate mongoid:config [DATABASE_NAME] [options]&lt;/code&gt;.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# spec/generators/mongoid/config/config_generator_spec.rb&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;spec_helper&amp;#39;&lt;/span&gt;

&lt;span class='c1'&gt;# Generators are not automatically loaded by Rails&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;rails/generators/mongoid/config/config_generator&amp;#39;&lt;/span&gt;

&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Application&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;MyApp&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Application&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Application&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;Mongoid&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Generators&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;ConfigGenerator&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='c1'&gt;# Tell the generator where to put its output (what it thinks of as Rails.root)&lt;/span&gt;
  &lt;span class='n'&gt;destination&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;expand_path&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;../../../../../../tmp&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='bp'&gt;__FILE__&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;prepare_destination&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;

  &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;no arguments&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;run_generator&lt;/span&gt;  &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;config/mongoid.yml&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;subject&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;file&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;config/mongoid.yml&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;exist&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;contain&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;database: my_app_development&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;specifying database name&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;run_generator&lt;/span&gt; &lt;span class='sx'&gt;%w(my_database)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;config/mongoid.yml&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;subject&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;file&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;config/mongoid.yml&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;exist&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;contain&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;database: my_database_development&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;There&amp;#8217;s some boilerplate setup you&amp;#8217;ll need at the top of your spec:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Since this spec file is in &lt;em&gt;spec/generators&lt;/em&gt; it automatically uses ammeter&lt;/li&gt;

&lt;li&gt;Generators are not automatically loaded by Rails&amp;#8217; &lt;em&gt;const_missing&lt;/em&gt; so we need to &lt;em&gt;require&lt;/em&gt; it explicitly&lt;/li&gt;

&lt;li&gt;&lt;em&gt;destination&lt;/em&gt; tells the generator where to put its output (we add enough &amp;#8220;../&amp;#8221;s to get us out of the spec directory)&lt;/li&gt;

&lt;li&gt;&lt;em&gt;before { prepare_destination }&lt;/em&gt; clears the destination so each spec starts fresh (similar to active record rollback)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now for the behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;run_generator&lt;/em&gt; runs the generator (optionally letting you pass in arguments)&lt;/li&gt;

&lt;li&gt;&lt;em&gt;file&lt;/em&gt; gives you access to a generated file&lt;/li&gt;

&lt;li&gt;&lt;em&gt;it should exist&lt;/em&gt; makes sure the file was generated&lt;/li&gt;

&lt;li&gt;&lt;em&gt;it should contain&lt;/em&gt; looks inside a generated file for a string or regex&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you&amp;#8217;re generating migrations it is somewhat tricky because migration file names contain a timestamp. We need another example and will use acts_as_taggable-on&amp;#8217;s &lt;a href='https://github.com/mbleigh/acts-as-taggable-on/blob/master/lib/generators/acts_as_taggable_on/migration/migration_generator.rb'&gt;migration generator&lt;/a&gt; We could write a spec for this as&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# spec/generators/acts_as_taggable_on/migration/migration_generator_spec.rb&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;spec_helper&amp;#39;&lt;/span&gt;

&lt;span class='c1'&gt;# Generators are not automatically loaded by Rails&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;generators/acts_as_taggable_on/migration/migration_generator&amp;#39;&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;ActsAsTaggableOn&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;MigrationGenerator&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='c1'&gt;# Tell the generator where to put its output (what it thinks of as Rails.root)&lt;/span&gt;
  &lt;span class='n'&gt;destination&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;expand_path&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;../../../../../tmp&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='bp'&gt;__FILE__&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

  &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;prepare_destination&lt;/span&gt;
    &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Generators&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:rails&lt;/span&gt;&lt;span class='o'&gt;][&lt;/span&gt;&lt;span class='ss'&gt;:orm&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='ss'&gt;:active_record&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;no arguments&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;run_generator&lt;/span&gt;  &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;db/migrate/acts_as_taggable_on_migration.rb&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;subject&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;file&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;db/migrate/acts_as_taggable_on_migration.rb&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
      &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;be_a_migration&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You can see much of the same setup and then the new matcher&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;it { should be_a_migration }&lt;/em&gt; which adds a timestamp to the filename&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='why_ammeter'&gt;Why &amp;#8216;Ammeter&amp;#8217;?&lt;/h2&gt;

&lt;p&gt;An &lt;a href='http://en.wikipedia.org/wiki/Ammeter'&gt;Ammeter&lt;/a&gt; is a measuring instrument used to measure the electric current in a circuit. Generators produce electricity and your specs measure your generators &amp;#8230; cute huh :)&lt;/p&gt;

&lt;h2 id='feedback_welcome'&gt;Feedback Welcome&lt;/h2&gt;

&lt;p&gt;Try Ammeter for your generators, I hope you find it useful. If it doesn&amp;#8217;t meet your needs fork away - &lt;a href='https://github.com/alexrothenberg/ammeter'&gt;Ammeter is on github&lt;/a&gt;. I welcome any feedback, issues or pull requests.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/3Ftlim7PNSA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/10/10/ammeter-the-way-to-write-specs-for-your-rails-generators.html</feedburner:origLink></entry>
 
 <entry>
   <title>Upgrading An Old Rails Rails 2.1.1 to 3.1 on Heroku</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/VkVG1a3LpnY/upgrading-an-old-rails-2-app-to-3.1-on-heroku.html" />
   <published>2011-10-03T00:00:00-07:00</published>
   <updated>2011-10-03T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2011/10/03/upgrading-an-old-rails-2-app-to-3.1-on-heroku</id>
   <content type="html">&lt;p&gt;I recently had to upgrade an old app and it went pretty smoothly so I thought I&amp;#8217;d share how I did it.&lt;/p&gt;

&lt;p&gt;I thought about two approaches to this upgrade&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I could slowly add modernity to the existing app by adding bundler, upgrading rails, upgrading rspec, etc.&lt;/li&gt;

&lt;li&gt;I could create a new Rails 3.1 project and copy the code and specs into this new project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I downloaded the old code and immediately remembered the pain of getting an app up and running without bundler. This convinced me that #1 would be harder than it needed to be so I decided to go with approach #2. It worked out pretty well so I&amp;#8217;m going to share exactly what I did.&lt;/p&gt;

&lt;h2 id='create_a_new_rails_31_project'&gt;Create a new Rails 3.1 project&lt;/h2&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; rails new waywework
&lt;span class='go'&gt;      create&lt;/span&gt;
&lt;span class='go'&gt;      create  README&lt;/span&gt;
&lt;span class='go'&gt;      create  Rakefile&lt;/span&gt;
&lt;span class='go'&gt;      # and a lot more...&lt;/span&gt;
&lt;span class='go'&gt;         run  bundle install&lt;/span&gt;
&lt;span class='go'&gt;Fetching source index for http://rubygems.org/&lt;/span&gt;
&lt;span class='go'&gt;Using rake (0.9.2)&lt;/span&gt;
&lt;span class='gp'&gt;#&lt;/span&gt; and a lot more...
&lt;span class='go'&gt;Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='add_gems_from_my_app'&gt;Add gems from my app&lt;/h2&gt;

&lt;p&gt;Because the old app comes from the days before bundler I had to look in &lt;code&gt;config/environment.rb&lt;/code&gt; for lines like &lt;code&gt;config.gem &amp;#39;atom&amp;#39;&lt;/code&gt; and guess what else I needed (I knew I was using rspec).&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;#Gemfile&lt;/span&gt;
&lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;atom&amp;#39;&lt;/span&gt;
&lt;span class='n'&gt;group&lt;/span&gt; &lt;span class='ss'&gt;:development&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:test&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;rspec-rails&amp;quot;&lt;/span&gt;
  &lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;factory_girl_rails&amp;quot;&lt;/span&gt;
  &lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;haml-rails&amp;quot;&lt;/span&gt;
  &lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;faker&amp;#39;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we can make sure our empty app works (even though it does nothing)&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; &lt;span class='nb'&gt;cd &lt;/span&gt;waywework
&lt;span class='gp'&gt;$&lt;/span&gt; rails g rspec:install
&lt;span class='go'&gt;      create  .rspec&lt;/span&gt;
&lt;span class='go'&gt;      create  spec&lt;/span&gt;
&lt;span class='go'&gt;      create  spec/spec_helper.rb&lt;/span&gt;
&lt;span class='gp'&gt;$&lt;/span&gt; rake db:migrate
&lt;span class='gp'&gt;$&lt;/span&gt; rake
&lt;span class='go'&gt;No examples matching ./spec/**/*_spec.rb could be found&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='add_our_existing_code_and_specs'&gt;Add our existing code and specs&lt;/h2&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; cp -r ~/old_waywework/app/controllers/* app/controllers
&lt;span class='gp'&gt;$&lt;/span&gt; cp -r ~/old_waywework/app/models/* app/models
&lt;span class='gp'&gt;$&lt;/span&gt; cp -r ~/old_waywework/app/helpers/* app/helpers
&lt;span class='gp'&gt;$&lt;/span&gt; cp -r ~/old_waywework/app/views/* app/views
&lt;span class='gp'&gt;$&lt;/span&gt; cp -r ~/old_waywework/db/migrate db
&lt;span class='gp'&gt;$&lt;/span&gt; mv spec/spec_helper.rb new_spec_helper.rb
&lt;span class='gp'&gt;$&lt;/span&gt; cp -r ~/old_waywework/spec/* spec
&lt;span class='gp'&gt;$&lt;/span&gt; mv new_spec_helper.rb spec/spec_helper.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now when we try to run the specs it tells us we have pending migrations so we run them&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; rake
&lt;span class='go'&gt;You have 5 pending migrations:&lt;/span&gt;
&lt;span class='go'&gt;  20081022162743 CreateFeeds&lt;/span&gt;
&lt;span class='go'&gt;  20081022162832 CreatePosts&lt;/span&gt;
&lt;span class='go'&gt;  20081031025747 IndexPublishedInPosts&lt;/span&gt;
&lt;span class='go'&gt;  20081031143453 IndexFeedAuthor&lt;/span&gt;
&lt;span class='go'&gt;  20081103143931 PublishedAsDatetime&lt;/span&gt;
&lt;span class='gp'&gt;$&lt;/span&gt; rake db:migrate
&lt;span class='go'&gt;==  CreateFeeds: migrating ====================================================&lt;/span&gt;
&lt;span class='go'&gt;-- create_table(:feeds)&lt;/span&gt;
&lt;span class='go'&gt;   -&amp;gt; 0.0025s&lt;/span&gt;
&lt;span class='go'&gt;==  CreateFeeds: migrated (0.0026s) ===========================================&lt;/span&gt;

&lt;span class='go'&gt;==  CreatePosts: migrating ====================================================&lt;/span&gt;
&lt;span class='go'&gt;-- create_table(:posts)&lt;/span&gt;
&lt;span class='go'&gt;   -&amp;gt; 0.0021s&lt;/span&gt;
&lt;span class='go'&gt;==  CreatePosts: migrated (0.0023s) ===========================================&lt;/span&gt;

&lt;span class='go'&gt;==  IndexPublishedInPosts: migrating ==========================================&lt;/span&gt;
&lt;span class='go'&gt;-- add_index(:posts, [:published, :feed_id])&lt;/span&gt;
&lt;span class='go'&gt;   -&amp;gt; 0.0015s&lt;/span&gt;
&lt;span class='go'&gt;==  IndexPublishedInPosts: migrated (0.0017s) =================================&lt;/span&gt;

&lt;span class='go'&gt;==  IndexFeedAuthor: migrating ================================================&lt;/span&gt;
&lt;span class='go'&gt;-- add_index(:feeds, :author)&lt;/span&gt;
&lt;span class='go'&gt;   -&amp;gt; 0.0007s&lt;/span&gt;
&lt;span class='go'&gt;==  IndexFeedAuthor: migrated (0.0008s) =======================================&lt;/span&gt;

&lt;span class='go'&gt;==  PublishedAsDatetime: migrating ============================================&lt;/span&gt;
&lt;span class='go'&gt;-- change_column(:posts, :published, :datetime)&lt;/span&gt;
&lt;span class='go'&gt;   -&amp;gt; 0.0086s&lt;/span&gt;
&lt;span class='go'&gt;-- add_column(:posts, :updated, :datetime)&lt;/span&gt;
&lt;span class='go'&gt;   -&amp;gt; 0.0006s&lt;/span&gt;
&lt;span class='go'&gt;==  PublishedAsDatetime: migrated (0.0094s) ===================================&lt;/span&gt;
&lt;span class='gp'&gt;$&lt;/span&gt; rake
&lt;span class='go'&gt;...LOTS OF ERRORS...&lt;/span&gt;
&lt;span class='go'&gt;activerecord-3.1.0/lib/active_record/base.rb:1083:&lt;/span&gt;
&lt;span class='go'&gt;    in `method_missing&amp;#39;: undefined method `named_scope&amp;#39; for #&amp;lt;Class:0x103875b28&amp;gt; (NoMethodError)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we&amp;#8217;re getting some errors and are ready to get to work.&lt;/p&gt;

&lt;h2 id='update_our_code'&gt;Update our code&lt;/h2&gt;

&lt;p&gt;Of course it doesn&amp;#8217;t just work and we need to make a number of changes. The guides include an &lt;a href='https://github.com/jm/rails_upgrade'&gt;upgrade process&lt;/a&gt; section and the &lt;a href='https://github.com/jm/rails_upgrade'&gt;rails_upgrade plugin&lt;/a&gt; can help identify problems. Here are the ones I found.&lt;/p&gt;

&lt;h3 id='changing__to_'&gt;Changing &lt;code&gt;named_scope&lt;/code&gt; to &lt;code&gt;scope&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;With Rails 3 the syntax for scopes changed from &lt;code&gt;named_scope&lt;/code&gt; to &lt;code&gt;scope&lt;/code&gt;. So we search-and-replace in our models. Once we do this the specs run, but many are failing. A lot are failing because the &lt;code&gt;routes.rb&lt;/code&gt; syntax changed in Rails 3.&lt;/p&gt;

&lt;h3 id='rails_root__railsroot'&gt;RAILS_ROOT =&amp;gt; Rails.root&lt;/h3&gt;

&lt;p&gt;The constant RAILS_ROOT no longer exists so we need to search-and-replace that with Rails.root.&lt;/p&gt;

&lt;h3 id='routesrb'&gt;Routes.rb&lt;/h3&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# OLD config/routes.rb&lt;/span&gt;
&lt;span class='no'&gt;ActionController&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Routing&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Routes&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;draw&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;posts_by_author&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;author/:id&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:controller&lt;/span&gt;&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:action&lt;/span&gt;&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;by_author&amp;#39;&lt;/span&gt;
  &lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;posts_by_month&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;month/:year/:month&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:controller&lt;/span&gt;&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:action&lt;/span&gt;&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;by_month&amp;#39;&lt;/span&gt;
  &lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;atom_feed&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/atom&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:controller&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;posts&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:action&lt;/span&gt;&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;index&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:format&lt;/span&gt;&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;atom&amp;#39;&lt;/span&gt;

  &lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;resources&lt;/span&gt; &lt;span class='ss'&gt;:feeds&lt;/span&gt;
  &lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;root&lt;/span&gt; &lt;span class='ss'&gt;:controller&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;posts&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We change it to:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# NEW config/routes.rb&lt;/span&gt;
&lt;span class='no'&gt;WayWeWork&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Application&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;routes&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;draw&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;match&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;author/:id&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;posts#by_author&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:as&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:posts_by_author&lt;/span&gt;
  &lt;span class='n'&gt;match&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;month/:year/:month&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;posts#by_month&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:as&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:posts_by_month&lt;/span&gt;
  &lt;span class='n'&gt;match&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/atom&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;posts#index&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:as&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:atom_feed&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:format&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:atom&lt;/span&gt;

  &lt;span class='n'&gt;resources&lt;/span&gt; &lt;span class='ss'&gt;:feeds&lt;/span&gt;

  &lt;span class='n'&gt;root&lt;/span&gt; &lt;span class='ss'&gt;:to&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;posts#index&amp;#39;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id='rspec_routing_specs'&gt;RSpec Routing Specs&lt;/h3&gt;

&lt;p&gt;We have a bunch of routing specs that are failing because RSpec changed the syntax around routing specs.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# OLD spec/controllers/feeds_routing_spec.rb&lt;/span&gt;
&lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should map #index&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;route_for&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:controller&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;feeds&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:action&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;index&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/feeds&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should generate params for #index&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;params_from&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:get&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/feeds&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='ss'&gt;:controller&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;feeds&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:action&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;index&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The routing spec must be in folder called &lt;code&gt;routing&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# NEW spec/feeds_routing_spec.rb&lt;/span&gt;
&lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;should generate params for #index&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;/feeds&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;route_to&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;feeds#index&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id='rspec_'&gt;RSpec &lt;code&gt;stub!&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Another syntax change in RSpec from using &lt;code&gt;stubs&lt;/code&gt; to &lt;code&gt;stub!&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# OLD&lt;/span&gt;
&lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;should ...&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='c1'&gt;#...&lt;/span&gt;
  &lt;span class='n'&gt;feed&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stubs&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:puts&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='n'&gt;feed&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;get_latest&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We get an error &lt;code&gt;undefined method &amp;#39;stubs&amp;#39; for \#&amp;lt;Feed:0x105d572e8&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# NEW&lt;/span&gt;
&lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;should ...&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='c1'&gt;#...&lt;/span&gt;
  &lt;span class='n'&gt;feed&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stub!&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:puts&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='n'&gt;feed&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;get_latest&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id='view_specs'&gt;View Specs&lt;/h3&gt;

&lt;p&gt;Hmm I&amp;#8217;m surprised I had written view specs. Nowadays I would write cucumber features and never write view specs. That being said there were a few things I needed to change to get the view specs passing, all related to RSpec syntax changes.&lt;/p&gt;

&lt;p&gt;I was passing @ variables to the view with &lt;code&gt;assigns[:feed] = @feed = stub_model(Feed)&lt;/code&gt; and today you need to do that with &lt;code&gt;assign(:feed, @feed = stub_model(Feed)&lt;/code&gt;. Also when you call &lt;code&gt;render &amp;quot;/feeds/edit.html.erb&amp;quot;&lt;/code&gt; it used to work but now tries to render a partial. Plain old &lt;code&gt;render&lt;/code&gt; will work as long as you&amp;#8217;ve put the filename in your describe like &lt;code&gt;describe &amp;quot;/feeds/edit.html.erb&amp;quot; do&lt;/code&gt;&lt;/p&gt;

&lt;h2 id='deploying_to_heroku'&gt;Deploying to Heroku&lt;/h2&gt;

&lt;p&gt;The old app was deployed to a VPS using Capistrano. Today I prefer to use Heroku and there were a few changes I had to make to get it working there.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;pg&lt;/code&gt; to my Gemfile to support Postgresql&lt;/li&gt;

&lt;li&gt;Configure assets (since we cannot write to the filesystem) ** Added &lt;code&gt;config.assets.compile = true&lt;/code&gt; in my production.rb ** Added &lt;code&gt;therubyracer&lt;/code&gt; to my Gemfile&lt;/li&gt;

&lt;li&gt;Delete my old &lt;code&gt;Capfile&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now I was able to deploy to heroku and the new app is up and running. All this done in less than a day!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/VkVG1a3LpnY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/10/03/upgrading-an-old-rails-2-app-to-3.1-on-heroku.html</feedburner:origLink></entry>
 
 <entry>
   <title>Talk Ruby to a Ruby Class instead of JSON to an HTTP Service</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/BiENyil4iIw/talk-ruby-to-a-ruby-class-instead-of-json-to-an-http-service.html" />
   <published>2011-09-26T00:00:00-07:00</published>
   <updated>2011-09-26T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2011/09/26/talk-ruby-to-a-ruby-class-instead-of-json-to-an-http-service</id>
   <content type="html">&lt;p&gt;Software as a service (&lt;a href='http://en.wikipedia.org/wiki/Software_as_a_service'&gt;SaaS&lt;/a&gt;) is a great thing. I love that other people are providing services and I don&amp;#8217;t have to implement them myself. I can use &lt;a href='http://airbrakeapp.com'&gt;Airbrake&lt;/a&gt; for error notifications and even &lt;a href='https://twitter.com/'&gt;Twitter&lt;/a&gt; for communication. It frees me to focus on what&amp;#8217;s unique about my app. Its great that they all work with open standards like HTTP, JSON and XML. But what I like even more is &lt;strong&gt;not having to think about HTTP, JSON or XML&lt;/strong&gt;! When writing a Ruby application I want to think about Ruby. The services I really like provide a gem that hides the transport api details and lets me write plain ruby.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href='https://github.com/thoughtbot/airbrake'&gt;Airbrake gem&lt;/a&gt; lets me write &lt;code&gt;Airbrake.notify(ex)&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;The &lt;a href='https://github.com/jnunemaker/twitter'&gt;Twitter gem&lt;/a&gt; lets me write &lt;code&gt;Twitter.user_timeline(&amp;quot;sferik&amp;quot;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are creating a service yourself or even using someone else&amp;#8217;s service it&amp;#8217;s not too hard to create your own client gem. Let&amp;#8217;s look at an example how we can do that.&lt;/p&gt;

&lt;h1 id='an_example_user_directory_service'&gt;An Example: User Directory Service&lt;/h1&gt;

&lt;p&gt;Imagine you&amp;#8217;re building a user directory that lets you list users, create users, update users, show users, delete users, you know, the standard RESTFUL actions. For instance we could create a user and list all users like this&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;[~]$ curl -F &amp;#39;user[name]&amp;#39;=&amp;#39;Mickey Mouse&amp;#39; http://user-directory.example.com/users.json&lt;/span&gt;
&lt;span class='go'&gt;{&amp;quot;user&amp;quot;:{&amp;quot;name&amp;quot;:&amp;quot;Mickey Mouse&amp;quot;,&amp;quot;id&amp;quot;:1001}}&lt;/span&gt;

&lt;span class='go'&gt;[~]$ curl http://user-directory.example.com/users.json&lt;/span&gt;
&lt;span class='go'&gt;[{&amp;quot;user&amp;quot;:{&amp;quot;name&amp;quot;:&amp;quot;Mickey Mouse&amp;quot;,&amp;quot;id&amp;quot;:1001}}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This is great to use from CURL but writing the code to talk http form fields and parse json will get pretty tiring. I&amp;#8217;d much rather have a &lt;code&gt;UserDirectory::User&lt;/code&gt; object that behaved similarly to an ActiveRecord model. When we&amp;#8217;re done we want to be able to have it work this&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;user&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:name&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Jenny&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:phone&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;867-5309&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; #&amp;lt;UserDirectory::User:0x10239b0b8 @name=&amp;quot;Jenny&amp;quot;, @phone=&amp;quot;867-5309&amp;quot;, @id=1001&amp;gt;&lt;/span&gt;
&lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;name&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; &amp;#39;Jenny&amp;#39;&lt;/span&gt;
&lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;id&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; 1001&lt;/span&gt;

&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;all&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; [ #&amp;lt;UserDirectory::User:0x102375638 @name=&amp;quot;Jenny&amp;quot;, @phone=&amp;quot;867-5309&amp;quot;, @id=1001&amp;gt;  ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h1 id='building_our_client_gem'&gt;Building our client gem&lt;/h1&gt;

&lt;p&gt;We&amp;#8217;ll want to wrap this client into a gem so it can be reused by many applications. I prefer to use bundler and its &lt;code&gt;bundle gem&lt;/code&gt; command to start my gem. I&amp;#8217;ll assume you know how to do that - check out this &lt;a href='http://railscasts.com/episodes/245-new-gem-with-bundler'&gt;railscast&lt;/a&gt; if you&amp;#8217;ve never done it before.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re going to get started by building a model class to represent the user without actually connecting it to our service yet.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;UserDirectory&lt;/span&gt;
  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;User&lt;/span&gt;
    &lt;span class='kp'&gt;include&lt;/span&gt; &lt;span class='no'&gt;ActiveModel&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Validations&lt;/span&gt;
    &lt;span class='n'&gt;validates_presence_of&lt;/span&gt; &lt;span class='ss'&gt;:name&lt;/span&gt;

    &lt;span class='kp'&gt;attr_accessor&lt;/span&gt; &lt;span class='ss'&gt;:name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:phone&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;attributes&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='p'&gt;{})&lt;/span&gt;
      &lt;span class='n'&gt;attributes&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;each&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;value&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
        &lt;span class='nb'&gt;send&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;=&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;value&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I hope you didn&amp;#8217;t think all model classes had to subclass &lt;code&gt;ActiveRecord::Base&lt;/code&gt;! For me a model represents a concept in the application domain and does not have to map to a database table!&lt;/p&gt;

&lt;p&gt;The magic in here is that we&amp;#8217;re mixing in the &lt;code&gt;ActiveModel::Validations&lt;/code&gt; module. This lets us add the same validations we would to a &amp;#8220;regular&amp;#8221; ActiveRecord model - in this case &lt;code&gt;validates_presence_of :name&lt;/code&gt;. When Rails 3.0 came along much of the functionality of ActiveRecord was extracted into ActiveModel which lets you &lt;a href='http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/'&gt;make any ruby object feel like ActiveRecord&lt;/a&gt; and as with most other topics Ryan Bates has put together a great &lt;a href='http://railscasts.com/episodes/219-active-model'&gt;railscast&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When we try it out it behaves as we expect.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# A valid user&lt;/span&gt;
&lt;span class='n'&gt;user&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:name&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;alex&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; #&amp;lt;UserDirectory::User:0x12b79fff0 @name=&amp;quot;alex&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;valid?&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; true&lt;/span&gt;

&lt;span class='c1'&gt;# an invalid user&lt;/span&gt;
&lt;span class='n'&gt;user&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:phone&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;555-1212&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; #&amp;lt;UserDirectory::User:0x12b78ecf0 @phone=&amp;quot;555-1212&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;valid?&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; false&lt;/span&gt;
&lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;errors&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; #&amp;lt;ActiveModel::Errors:0x12b788f80 @base=#&amp;lt;UserDirectory::User:0x12b78ecf0&lt;/span&gt;
&lt;span class='c1'&gt;#      @errors=#&amp;lt;ActiveModel::Errors:0x12b788f80 ...&amp;gt;, @validation_context=nil, @phone=&amp;quot;555-1212&amp;quot;&amp;gt;,&lt;/span&gt;
&lt;span class='c1'&gt;#      @messages=#&amp;lt;OrderedHash {:name=&amp;gt;[&amp;quot;can&amp;#39;t be blank&amp;quot;]}&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The next step is to make our model interact with the service using HTTP and JSON. I&amp;#8217;m going to be using the &lt;a href='https://github.com/jnunemaker/httparty'&gt;HTTParty gem&lt;/a&gt;. It is much easier to use than net/http and automatically parses json or xml into a ruby hash for us.&lt;/p&gt;

&lt;p&gt;First, we&amp;#8217;ll add a &lt;code&gt;create&lt;/code&gt; method that tells the service to create a new user as long as we pass our validations and then returns a &lt;code&gt;User&lt;/code&gt; instance.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;UserDirectory&lt;/span&gt;
  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;User&lt;/span&gt;
    &lt;span class='c1'&gt;# all the existing code and...&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;attributes&lt;/span&gt;
      &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='ss'&gt;:name&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:phone&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;phone&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='kp'&gt;include&lt;/span&gt; &lt;span class='no'&gt;HTTParty&lt;/span&gt;
    &lt;span class='n'&gt;base_uri&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;http://user-directory.example.com&amp;#39;&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nc'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='nf'&gt;create&lt;/span&gt; &lt;span class='n'&gt;attributes&lt;/span&gt;
      &lt;span class='n'&gt;user&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='kp'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;attributes&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt; &lt;span class='k'&gt;unless&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;valid?&lt;/span&gt;

      &lt;span class='n'&gt;response&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;post&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/users.json&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:body&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;attributes&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='k'&gt;raise&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;code&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;: Better error handling please&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;unless&lt;/span&gt; &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;success?&lt;/span&gt;
      &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;parsed_response&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We can do the same for an &lt;code&gt;all&lt;/code&gt; method that returns an array of all users stored in the service.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;UserDirectory&lt;/span&gt;
  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;User&lt;/span&gt;
    &lt;span class='c1'&gt;# all the existing code and...&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nc'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='nf'&gt;all&lt;/span&gt;
      &lt;span class='n'&gt;response&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/users.json&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='k'&gt;raise&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;code&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;: Better error handling please&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;unless&lt;/span&gt; &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;success?&lt;/span&gt;
      &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;parsed_response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;map&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;user_attributes&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
        &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt; &lt;span class='n'&gt;user_attributes&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Let&amp;#8217;s try it out.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# No users yet&lt;/span&gt;
&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;all&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; []&lt;/span&gt;

&lt;span class='c1'&gt;# Create a user&lt;/span&gt;
&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:name&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;alex&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:phone&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;555-1212&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; #&amp;lt;UserDirectory::User:0x12c52f0a8 @name=&amp;quot;alex&amp;quot;, @phone=&amp;quot;555-1212&amp;quot;&amp;gt;&lt;/span&gt;

&lt;span class='c1'&gt;# Now ask the service again&lt;/span&gt;
&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;all&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; [#&amp;lt;UserDirectory::User:0x12b8890d8 @name=&amp;quot;alex&amp;quot;, @phone=&amp;quot;555-1212&amp;quot;&amp;gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This is great! We have a class that&amp;#8217;s easy to use, behaves like a normal model but actually talks JSON and HTTP to a remote service. We could continue along the same lines to implement the other methods we need like &lt;code&gt;find&lt;/code&gt; &amp;amp; &lt;code&gt;destroy&lt;/code&gt; but I&amp;#8217;m not going to bore you with that here. Instead I&amp;#8217;ll switch gears and talk about building a fake service to eliminate the need to have the actual service running during development and testing.&lt;/p&gt;

&lt;h1 id='building_a_fake_service'&gt;Building a fake service&lt;/h1&gt;

&lt;p&gt;There are a few reasons we want to build a fake service.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It&amp;#8217;ll be faster to not make any network calls&lt;/li&gt;

&lt;li&gt;It&amp;#8217;s a lot of overhead to start a local copy of the service during development&lt;/li&gt;

&lt;li&gt;It&amp;#8217;ll be easier to test various failures (500 errors and the like)&lt;/li&gt;

&lt;li&gt;It allows us to setup and clear the data any way we want&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How do we create a fake service? Luckily there&amp;#8217;s a gem for that! The &lt;a href='https://github.com/mdub/sham_rack'&gt;ShamRack gem&lt;/a&gt; intercepts http calls before they leave our app and redirects them to a local Rack App we&amp;#8217;ll create. We&amp;#8217;ll create a simple sinatra app that implements the &lt;code&gt;UserDirectory Service API&lt;/code&gt; and embed it in our gem.&lt;/p&gt;

&lt;p&gt;First things first, add the gem to our gem&amp;#8217;s &lt;code&gt;user_directory_client.gemspec&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;gem&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;add_dependency&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;sham_rack&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we can&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;sinatra&amp;#39;&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;sham_rack&amp;#39;&lt;/span&gt;

&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;UserDirectory&lt;/span&gt;
  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;FakeService&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Sinatra&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;

    &lt;span class='c1'&gt;###################&lt;/span&gt;
    &lt;span class='c1'&gt;# ShamRack methods&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nc'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='nf'&gt;activate!&lt;/span&gt;
      &lt;span class='no'&gt;ShamRack&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;mount&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;user-directory.example.com&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;80&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nc'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='nf'&gt;deactivate!&lt;/span&gt;
      &lt;span class='no'&gt;ShamRack&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;unmount_all&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;


    &lt;span class='c1'&gt;###################&lt;/span&gt;
    &lt;span class='c1'&gt;# Sinatra methods&lt;/span&gt;
    &lt;span class='n'&gt;configure&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;set&lt;/span&gt; &lt;span class='ss'&gt;:raise_errors&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kp'&gt;true&lt;/span&gt;
      &lt;span class='n'&gt;set&lt;/span&gt; &lt;span class='ss'&gt;:show_exceptions&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kp'&gt;false&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='no'&gt;USER_JSON&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='ss'&gt;:name&lt;/span&gt;&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;Jenny&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:phone&lt;/span&gt;&lt;span class='o'&gt;=&amp;gt;&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;867-5309&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_json&lt;/span&gt;

    &lt;span class='n'&gt;get&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/users.json&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;content_type&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;text/json&amp;#39;&lt;/span&gt;
      &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='no'&gt;USER_JSON&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='c1'&gt;# :hardcoded list of 1 user&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='c1'&gt;# :create new user&lt;/span&gt;
    &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/users.json&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;content_type&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;text/json&amp;#39;&lt;/span&gt;
      &lt;span class='no'&gt;USER_JSON&lt;/span&gt; &lt;span class='c1'&gt;# pretend to create and return hardcoded user&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Its very simple and will always return the same hardcoded user but that might be enough. We turn the fake service on and off with calls to &lt;code&gt;UserDirectory::FakeService.activate!&lt;/code&gt; and &lt;code&gt;UserDirectory::FakeService.deactivate!&lt;/code&gt;. Let&amp;#8217;s take a look.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;FakeService&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;activate!&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; PeopleServices::FakePeopleService&lt;/span&gt;

&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;all&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; [#&amp;lt;UserDirectory::User:0x12c52f0a8 @name=&amp;quot;jenny&amp;quot;, @phone=&amp;quot;867-5309&amp;quot;&amp;gt;]&lt;/span&gt;

&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:name&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;alex&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:phone&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;555-1212&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; #&amp;lt;UserDirectory::User:0x12b8731e8 @name=&amp;quot;jenny&amp;quot;, @phone=&amp;quot;867-5309&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:name&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;pat&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; #&amp;lt;UserDirectory::User:0x12b86cc58 @name=&amp;quot;jenny&amp;quot;, @phone=&amp;quot;867-5309&amp;quot;&amp;gt;&lt;/span&gt;

&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;all&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; [#&amp;lt;UserDirectory::User:0x12b865cf0 @name=&amp;quot;jenny&amp;quot;, @phone=&amp;quot;867-5309&amp;quot;&amp;gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This is interesting. Its fast and eliminates the dependency, but its all hardcoded! When we created 2 users we still got the same &amp;#8220;Jenny&amp;#8221; user every time. The good news is the fake service is just a class we wrote so we can make is as complex as we need. Perhaps what we have here is enough for you and you&amp;#8217;re all done but we&amp;#8217;ll assume you want something a bit more realistic.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re going to create a quick array to simulate persisting our users.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;sinatra&amp;#39;&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;sham_rack&amp;#39;&lt;/span&gt;

&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;UserDirectory&lt;/span&gt;
  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;FakeService&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Sinatra&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;

    &lt;span class='c1'&gt;# ShamRack methods ... remain unchanged&lt;/span&gt;

    &lt;span class='c1'&gt;# Sinatra methods ... changed to use our new &amp;quot;business logic&amp;quot;&lt;/span&gt;
    &lt;span class='n'&gt;get&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/users.json&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;class&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;users&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_json&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='n'&gt;post&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/users.json&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;create_user&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='c1'&gt;###################&lt;/span&gt;
    &lt;span class='c1'&gt;# Some &amp;quot;business logic&amp;quot;&lt;/span&gt;
    &lt;span class='c1'&gt;# the worlds simplest db :)&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nc'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='nf'&gt;users&lt;/span&gt;
      &lt;span class='vi'&gt;@users&lt;/span&gt; &lt;span class='o'&gt;||=&lt;/span&gt; &lt;span class='o'&gt;[]&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;create_user&lt;/span&gt; &lt;span class='n'&gt;attributes&lt;/span&gt;
      &lt;span class='n'&gt;attributes&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;rand&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;10000&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;class&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;users&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;attributes&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;dup&lt;/span&gt;
      &lt;span class='n'&gt;attributes&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_json&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;One last time we&amp;#8217;re going to try it out.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;FakeService&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;activate!&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; PeopleServices::FakePeopleService&lt;/span&gt;

&lt;span class='c1'&gt;# We start off empty&lt;/span&gt;
&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;all&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; []&lt;/span&gt;

&lt;span class='c1'&gt;# Create some users - the attributes correctly change&lt;/span&gt;
&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:name&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;alex&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:phone&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;555-1212&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; #&amp;lt;UserDirectory::User:0x12b85f300 @name=&amp;quot;alex&amp;quot;, @phone=&amp;quot;555-1212&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:name&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;pat&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; #&amp;lt;UserDirectory::User:0x12b857880 @name=&amp;quot;pat&amp;quot;&amp;gt;&lt;/span&gt;

&lt;span class='c1'&gt;# Now we have our 2 users&lt;/span&gt;
&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;all&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; [#&amp;lt;UserDirectory::User:0x12b851318 @name=&amp;quot;alex&amp;quot;, @phone=&amp;quot;555-1212&amp;quot;&amp;gt;, #&amp;lt;UserDirectory::User:0x12b84adb0 @name=&amp;quot;pat&amp;quot;&amp;gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This is now looking almost like a real service and will be very useful as we do our development. One last enhancement is that it&amp;#8217;ll be nice to test what happens when the service has errors.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;sinatra&amp;#39;&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;sham_rack&amp;#39;&lt;/span&gt;

&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;UserDirectory&lt;/span&gt;
  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;FakeService&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;Sinatra&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Base&lt;/span&gt;
    &lt;span class='c1'&gt;# Everything else unchanged...&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nc'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='nf'&gt;fail_next_request!&lt;/span&gt;
      &lt;span class='vi'&gt;@fail_next_request&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='kp'&gt;true&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nc'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='nf'&gt;should_fail_request?&lt;/span&gt;
      &lt;span class='n'&gt;should_fail&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@fail_next_request&lt;/span&gt;
      &lt;span class='vi'&gt;@fail_next_request&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='kp'&gt;false&lt;/span&gt;
      &lt;span class='n'&gt;should_fail&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='c1'&gt;# Sinatra before filter&lt;/span&gt;
    &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;halt&lt;/span&gt; &lt;span class='mi'&gt;500&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;We were told to fail!&amp;#39;&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;class&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should_fail_request?&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;One last time we&amp;#8217;ll try it out.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;FakeService&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;activate!&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;FakeService&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;fail_next_request!&lt;/span&gt;
&lt;span class='c1'&gt;# =&amp;gt; true&lt;/span&gt;
 
&lt;span class='no'&gt;UserDirectory&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;User&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;create&lt;/span&gt; &lt;span class='ss'&gt;:name&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Alex&amp;#39;&lt;/span&gt;
&lt;span class='no'&gt;RuntimeError&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;500&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt; &lt;span class='no'&gt;We&lt;/span&gt; &lt;span class='n'&gt;were&lt;/span&gt; &lt;span class='n'&gt;told&lt;/span&gt; &lt;span class='n'&gt;to&lt;/span&gt; &lt;span class='nb'&gt;fail&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;
	&lt;span class='n'&gt;from&lt;/span&gt;&lt;span class='sr'&gt; /Users/&lt;/span&gt;&lt;span class='n'&gt;alex&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;user_directory_client&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;lib&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;user_directory&lt;/span&gt;&lt;span class='o'&gt;/&lt;/span&gt;&lt;span class='n'&gt;user&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;rb&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;&lt;span class='mi'&gt;25&lt;/span&gt;&lt;span class='ss'&gt;:in&lt;/span&gt; &lt;span class='sb'&gt;`create&amp;#39;&lt;/span&gt;
&lt;span class='sb'&gt;	from (irb):56&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now go off and create a client for any service you create and be sure to include a fake service!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/BiENyil4iIw" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/09/26/talk-ruby-to-a-ruby-class-instead-of-json-to-an-http-service.html</feedburner:origLink></entry>
 
 <entry>
   <title>Running a Private GemServer inside the Firewall</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/RURT_GCWAuY/running-a-private-gemserver-inside-the-firewall.html" />
   <published>2011-09-16T00:00:00-07:00</published>
   <updated>2011-09-16T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2011/09/16/running-a-private-gemserver-inside-the-firewall</id>
   <content type="html">&lt;p&gt;&lt;a href='http://rubygems.org'&gt;rubygems.org&lt;/a&gt; has made it so easy to publish a gem for the world to use but what do you do when your gem is proprietary and you only want to publish it within your company?&lt;/p&gt;

&lt;p&gt;This is something I&amp;#8217;ve just been through at my company and thought I&amp;#8217;d share the steps I went through. We need to&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setup an inside-the-firewall gem server&lt;/li&gt;

&lt;li&gt;Configure our gems to deploy to it&lt;/li&gt;

&lt;li&gt;Configure our apps to use it&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id='setup_an_insidethefirewall_gem_server'&gt;Setup an inside-the-firewall gem server&lt;/h2&gt;

&lt;p&gt;The first thing you have to decide is what gemserver to use. Rubygems.org has a helpful page called &lt;a href='http://guides.rubygems.org/run-your-own-gem-server/'&gt;running your own gemserver&lt;/a&gt; that basically lists 3 choices in a goldilocks situation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;too small&lt;/em&gt; - &lt;a href='http://docs.rubygems.org/read/chapter/18'&gt;gem server&lt;/a&gt; is a command built into rubygems&lt;/p&gt;

&lt;p&gt;This works but you need to log onto the server to install a new gem and it serves all gems on the system not just your proprietary ones&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;em&gt;too big&lt;/em&gt; - &lt;a href='https://github.com/rubygems/rubygems.org/wiki/Standup-your-own-Gemcutter'&gt;rubygems.org&lt;/a&gt; is open source so we could deploy it on our own server&lt;/p&gt;

&lt;p&gt;This seems pretty complex to setup and even they tell you to &amp;#8220;consider checking out Geminabox&amp;#8221;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;em&gt;just right&lt;/em&gt; - &lt;a href='https://github.com/cwninja/geminabox'&gt;gem in a box&lt;/a&gt; is a simple sinatra app to allow you to host your own in-house gems&lt;/p&gt;

&lt;p&gt;This is easy to setup, has a web interface and supports a command line to remotely publish new gems.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;geminabox&lt;/strong&gt; is what I decided to go with.&lt;/p&gt;

&lt;p&gt;The readme on github describes the &lt;a href='https://github.com/cwninja/geminabox'&gt;server setup for geminabox&lt;/a&gt; and it &lt;em&gt;just worked&lt;/em&gt;. The only thing to keep in mind is that you cannot use bundler as then you will only serve the gems in the bundle instead of the gems you publish. I spent some time adding bundler before realizing that was a bad idea and backing it out.&lt;/p&gt;

&lt;p&gt;Once geminabox is up and running you can view your gems at your internal url and you&amp;#8217;ll see the gem server homepage showing you it has no gems.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-09-16-running-a-private-gemserver-inside-the-firewall/geminabox_empty.png' alt='New Gem Server' /&gt;&lt;/p&gt;

&lt;p&gt;The easiest thing is to add a new gem by clicking &amp;#8220;Upload Another Gem&amp;#8221; and selecting a &lt;code&gt;.gem&lt;/code&gt; file from your hard drive (I picked &lt;code&gt;diagnostics-0.0.1.gem&lt;/code&gt; in the image below).&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-09-16-running-a-private-gemserver-inside-the-firewall/geminabox_upload.png' alt='Upload A Gem Manuallly' /&gt;&lt;/p&gt;

&lt;p&gt;Once you click &lt;code&gt;uppload&lt;/code&gt; you should see your gem on the page.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-09-16-running-a-private-gemserver-inside-the-firewall/geminabox_with_a_gem.png' alt='Gem Server With A Gem' /&gt;&lt;/p&gt;

&lt;p&gt;At this point we could start using this gem server in our apps but before we talk about that let&amp;#8217;s automate the manual process we just went through to add a gem.&lt;/p&gt;

&lt;h2 id='configure_our_gems_to_deploy_to_the_gem_server'&gt;Configure our gems to deploy to the gem server&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ve been using bundler to create my gems with the &lt;code&gt;bundle gem&lt;/code&gt; command and one of the features that gives you is a set of nice rake tasks. Check out the &lt;a href='http://railscasts.com/episodes/245-new-gem-with-bundler'&gt;New Gem with Bundler Railscast&lt;/a&gt; to learn how it works.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; bundle gem my_awesome_gem
&lt;span class='go'&gt;      create  my_awesome_gem/Gemfile&lt;/span&gt;
&lt;span class='go'&gt;      create  my_awesome_gem/Rakefile&lt;/span&gt;
&lt;span class='go'&gt;      create  my_awesome_gem/.gitignore&lt;/span&gt;
&lt;span class='go'&gt;      create  my_awesome_gem/my_awesome_gem.gemspec&lt;/span&gt;
&lt;span class='go'&gt;      create  my_awesome_gem/lib/my_awesome_gem.rb&lt;/span&gt;
&lt;span class='go'&gt;      create  my_awesome_gem/lib/my_awesome_gem/version.rb&lt;/span&gt;
&lt;span class='go'&gt;Initializating git repo in /Users/alex/my_awesome_gem&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Let&amp;#8217;s look at the tasks we&amp;#8217;ve got.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; &lt;span class='nb'&gt;cd &lt;/span&gt;my_awesome_gem
&lt;span class='gp'&gt;$&lt;/span&gt; rake -T
&lt;span class='go'&gt;rake build    # Build my_awesome_gem-0.0.1.gem into the pkg directory&lt;/span&gt;
&lt;span class='go'&gt;rake install  # Build and install my_awesome_gem-0.0.1.gem into system gems&lt;/span&gt;
&lt;span class='go'&gt;rake release  # Create tag v0.0.1 and build and push my_awesome_gem-0.0.1.gem to Rubygems&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;rake build&lt;/code&gt; and &lt;code&gt;rake install&lt;/code&gt; do their work locally but &lt;code&gt;rake release&lt;/code&gt; is what you call when you&amp;#8217;re &lt;em&gt;done&lt;/em&gt; and ready to release your gem into the wild. This task will push your changes to github, create a git tag, build your gem package and deploy it to http://rubygems.org. We need to do something to change that last part so it deploys to our private gem server instead of rubygems.org.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s spend some time looking into bundler to figure out how &lt;code&gt;rake release&lt;/code&gt; works. The magic all happens inside a file &lt;code&gt;lib/bundler/gem_helper.rb&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It defines a &lt;a href='https://github.com/carlhuda/bundler/blob/1-0-stable/lib/bundler/gem_helper.rb#L36-39'&gt;:release rake task&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;Which calls &lt;a href='https://github.com/carlhuda/bundler/blob/1-0-stable/lib/bundler/gem_helper.rb#L61-69'&gt;release_gem&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;Which calls &lt;a href='https://github.com/carlhuda/bundler/blob/1-0-stable/lib/bundler/gem_helper.rb#L72-79'&gt;rubygem_push&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;Finally this will call &lt;code&gt;gem push pkg/my_awesome_gem-0.0.1.gem&lt;/code&gt; which pushes to http://rubygems.org. We&amp;#8217;ve found the behavior we need to change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;geminabox adds a custom rubygems command called &lt;code&gt;inabox&lt;/code&gt; so you can deploy a gem with the command &lt;code&gt;gem inabox pkg/my-awesome-gem-1.0.gem&lt;/code&gt;. Unfortunately bundler does not seem to have a convenient way to change this so we&amp;#8217;re going to monkey patch bundler &lt;code&gt;Bundler::GemHelper#rugygem_push&lt;/code&gt; method to use the geminabox command instead. (&lt;em&gt;please&lt;/em&gt; let me know if you have a better idea)&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ll add our monkey patch to our &lt;code&gt;Rakefile&lt;/code&gt; since its called by a rake command.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# Rakefile in your my_awesome_gem gem&lt;/span&gt;

&lt;span class='c1'&gt;# Monkey patch Bundler gem_helper so we release to our gem server instead of rubygems.org&lt;/span&gt;
&lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;Bundler&lt;/span&gt;
  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;GemHelper&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;rubygem_push&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;path&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='n'&gt;gem_server_url&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;http://gems.intranet.mycompany.com&amp;#39;&lt;/span&gt;
      &lt;span class='n'&gt;sh&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;gem inabox &amp;#39;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;path&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;#39; --host &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;gem_server_url&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='no'&gt;Bundler&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;ui&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;confirm&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Pushed &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='nb'&gt;name&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;version&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt; to &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;gem_server_url&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You can see this will call &lt;code&gt;gem inabox ...&lt;/code&gt; so we also need to add &lt;code&gt;geminabox&lt;/code&gt; to our gem&amp;#8217;s bundle. We do this in the &lt;code&gt;.gemspec&lt;/code&gt; as a development dependency&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# my_awesome_gem.gemspec in your gem&lt;/span&gt;

&lt;span class='no'&gt;Gem&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Specification&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;s&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt; &lt;span class='n'&gt;lots&lt;/span&gt; &lt;span class='n'&gt;of&lt;/span&gt; &lt;span class='n'&gt;other&lt;/span&gt; &lt;span class='n'&gt;stuff&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;

  &lt;span class='n'&gt;s&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;add_development_dependency&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;geminabox&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now when we call &lt;code&gt;rake release&lt;/code&gt; it will push the gem to our private server instead of the public one. Let&amp;#8217;s see:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; rake release
&lt;span class='go'&gt;my_awesome_gem 0.0.1 built to pkg/my_awesome_gem-0.0.1.gem&lt;/span&gt;
&lt;span class='go'&gt;Tagged v0.0.1&lt;/span&gt;
&lt;span class='go'&gt;Pushed git commits and tags&lt;/span&gt;
&lt;span class='go'&gt;Pushed my_awesome_gem 0.0.1 to http://gems.intranet.mycompany.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now when we go to the gem server site, we can see our new awesome gem in the list&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/images/2011-09-16-running-a-private-gemserver-inside-the-firewall/geminabox_with_awesome_gem.png' alt='Gem Server With Awesome Gem' /&gt;&lt;/p&gt;

&lt;p&gt;The gem is there an you can use install it with a command like &lt;code&gt;gem install my_awesome_gem --source http://gems.intranet.mycompany.com&lt;/code&gt;&lt;/p&gt;

&lt;h2 id='using_your_gem_server_from_an_application'&gt;Using your Gem Server from an application&lt;/h2&gt;

&lt;p&gt;We&amp;#8217;ve just seen how we can use the &lt;code&gt;source&lt;/code&gt; option to tell rubygems where to look when installing our gem by hand, but in a modern application we all use &lt;code&gt;bundler&lt;/code&gt; and a &lt;code&gt;Gemfile&lt;/code&gt; to manage our gems so how do we tell bundler to user our private gemserver for our private gems? Its super simple, you just need to add a &lt;code&gt;source&lt;/code&gt; to the top of your &lt;code&gt;Gemfile&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;source&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;http://gems.intranet.mycompany.com/&amp;quot;&lt;/span&gt;
&lt;span class='n'&gt;source&lt;/span&gt; &lt;span class='ss'&gt;:rubygems&lt;/span&gt;

&lt;span class='c1'&gt;# regular old gems come from rubygems.org&lt;/span&gt;
&lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;rails&amp;quot;&lt;/span&gt;
&lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;rack&amp;quot;&lt;/span&gt;
&lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;haml&amp;quot;&lt;/span&gt;

&lt;span class='c1'&gt;# my private gem comes from my private gemserver&lt;/span&gt;
&lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;diagnostics&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now when we run &lt;code&gt;bundle&lt;/code&gt; it looks in our private gem server as well as the public rubygems.org. Now that that you&amp;#8217;ve got my_awesoem_gem you&amp;#8217;re ready to add awesomeness to your app.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='gp'&gt;$&lt;/span&gt; bundle
&lt;span class='go'&gt;Fetching source index for http://gems.intranet.mycompany.com/&lt;/span&gt;
&lt;span class='go'&gt;Fetching source index for http://rubygems.org/&lt;/span&gt;
&lt;span class='go'&gt;Using rake (0.9.2)&lt;/span&gt;
&lt;span class='go'&gt;Using activesupport (3.1.0)&lt;/span&gt;
&lt;span class='go'&gt;Installing my_awesome_gem (0.0.1)&lt;/span&gt;
&lt;span class='go'&gt;...etc..&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/RURT_GCWAuY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/09/16/running-a-private-gemserver-inside-the-firewall.html</feedburner:origLink></entry>
 
 <entry>
   <title>How Bundler Groups relate to the Rails Environment</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/Brt1kVcqIGw/how-bundler-groups-relate-to-the-rails-environment.html" />
   <published>2011-07-18T00:00:00-07:00</published>
   <updated>2011-07-18T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2011/07/18/how-bundler-groups-relate-to-the-rails-environment</id>
   <content type="html">&lt;p&gt;Recently I&amp;#8217;ve seen more and more Gemfiles that organize gems into groups and it got me wondering how bundler knows which groups to load. For the most part two things happen&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;At install time - Bundler includes a capistrano task that installs all gems except those only in the development or test groups on your server&lt;/li&gt;

&lt;li&gt;At execution time - Rails tells bundler to load the default gems and those specific to your environment (development, staging or production)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id='how_bundler_installs_gems_into_your_bundle'&gt;How Bundler installs gems into your bundle&lt;/h2&gt;

&lt;p&gt;To tell bundler to use bundler on the server all you need to do is add the one line below to your Capfile&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;bundler/capistrano&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This creates a capistrano task &lt;code&gt;bundle:install&lt;/code&gt; that ultimately runs something like the command below on your server&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;bundle install --gemfile /srv/my_app/releases/20110715204318/Gemfile --path /srv/my_app/shared/bundle
               --deployment --quiet --without development &lt;span class='nb'&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Okay so it ran a &lt;code&gt;bundle install&lt;/code&gt; but what really happened? Let&amp;#8217;s take that command one piece at a time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--gemfile /srv/my_app/releases/20110715204318/Gemfile&lt;/code&gt; tells it to use our Gemfile, that makes sense.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;code&gt;--path /srv/my_app/shared/bundle&lt;/code&gt; tells it where to put the bundle. Let&amp;#8217;s see what that means.&lt;/p&gt;

&lt;p&gt;It looks like it created all the &lt;code&gt;rubygems&lt;/code&gt; directories for to isolate the gems for this project (very similarly to &lt;a href='http://beginrescueend.com/gemsets'&gt;rvm gemsets&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;    &lt;span class='nv'&gt;$ &lt;/span&gt;ls /srv/my_app/shared/bundle/
    ruby
    &lt;span class='nv'&gt;$ &lt;/span&gt;ls /srv/my_app/shared/bundle/ruby/
    1.8
    &lt;span class='nv'&gt;$ &lt;/span&gt;ls /srv/my_app/shared/bundle/ruby/1.8/
    bin  cache  doc  gems  specifications
    
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--quiet&lt;/code&gt; hmm what else can I say&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;code&gt;--without development test&lt;/code&gt; Aha so here&amp;#8217;s where it tells bundler to skip the &lt;code&gt;development&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; groups. so allall gems outside a group or in a group other than &lt;code&gt;development&lt;/code&gt; or &lt;code&gt;test&lt;/code&gt; are installed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How does Bundler remember these settings when it loads Rails and tries to load the bundle? It saves them away in a &lt;code&gt;.bundle&lt;/code&gt; directory &lt;code&gt;cat .bundle/config&lt;/code&gt; shows us&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='yaml'&gt;&lt;span class='nn'&gt;---&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;BUNDLE_FROZEN&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;BUNDLE_DISABLE_SHARED_GEMS&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;BUNDLE_WITHOUT&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;development:test&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;BUNDLE_PATH&lt;/span&gt;&lt;span class='p-Indicator'&gt;:&lt;/span&gt; &lt;span class='l-Scalar-Plain'&gt;/srv/my_app/shared/bundle&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we understand how Bundler and Capistrano work together during a deployment to setup the bundle and install gems on the server. Let&amp;#8217;s take a look at what happens when our app starts up.&lt;/p&gt;

&lt;h2 id='how_rails_and_bundler_load_your_gems_according_to_the_rails_environment'&gt;How Rails and Bundler load your gems according to the Rails Environment&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;config/application.rb&lt;/code&gt;, right near the top, you have a line like this.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='yaml'&gt;&lt;span class='c1'&gt;# If you have a Gemfile, require the gems listed there, including any gems&lt;/span&gt;
&lt;span class='c1'&gt;# you&amp;#39;ve limited to :test, :development, or :production.&lt;/span&gt;
&lt;span class='l-Scalar-Plain'&gt;Bundler.require(:default, Rails.env) if defined?(Bundler)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Rails tells bundler to require all the gems in the &lt;code&gt;:default&lt;/code&gt; group and also the current &lt;code&gt;Rails.env&lt;/code&gt; group. It uses the &lt;code&gt;.bundle/config&lt;/code&gt; file to know where the gems are installed and find them. So that&amp;#8217;s how the gems appropriate for your environment get automatically loaded when Rails starts.&lt;/p&gt;

&lt;h2 id='what_if_you_create_a_gem_group_that_doesnt_correspond_to_any_rails_env'&gt;What if you create a gem group that doesn&amp;#8217;t correspond to any Rails env?&lt;/h2&gt;

&lt;p&gt;This is the problem that started me down this investigation. I came across a &lt;code&gt;Gemfile&lt;/code&gt; with a group called &lt;code&gt;cruise&lt;/code&gt; like this&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;group&lt;/span&gt; &lt;span class='ss'&gt;:cruise&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;metric_fu&amp;#39;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It was working meaning our cruise server ran &lt;a href='http://metric-fu.rubyforge.org/'&gt;metric_fu&lt;/a&gt; but why?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;We weren&amp;#8217;t using capistrano to run bundle install and instead just checked whether we were on our cruise server and ran the command &lt;code&gt;bundle install&lt;/code&gt; in our Rakefile. &lt;em&gt;Aside: We are looking into &lt;a href='http://jenkins-ci.org/'&gt;Jenkins&lt;/a&gt; as a continuous integration server that supports bundler&lt;/em&gt; This explains why the &lt;code&gt;metric_fu&lt;/code&gt; was installed into our bundle (there was no &lt;code&gt;--without&lt;/code&gt; so all gems are installed)&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;When our Rails app starts it would not load metric_fu becuase &lt;code&gt;Rails.env&lt;/code&gt; will never be &lt;code&gt;cruise&lt;/code&gt; when the &lt;code&gt;application.rb&lt;/code&gt; line &lt;code&gt;Bundler.require(:default, Rails.env)&lt;/code&gt; runs. We had worked around that by doing the require ourselves.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;   &lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;metric_fu&amp;#39;&lt;/span&gt;
   
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;While this does work in that our cruise build works it has the downside of installing &lt;code&gt;metric_fu&lt;/code&gt; (and all the gems it depends on) on our production server! That&amp;#8217;s because the &lt;code&gt;bundler/capistrano&lt;/code&gt; task installs all gems not marked &lt;code&gt;development&lt;/code&gt; or &lt;code&gt;test&lt;/code&gt; and since &lt;code&gt;metric_fu&lt;/code&gt; is marked &lt;code&gt;cruise&lt;/code&gt; it gets installed. Now Rails will not load it so its not that bad but its still not good. We can take a quick look on our server to verify&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='nv'&gt;$ &lt;/span&gt;ls /srv/my_app/shared/bundle/ruby/1.8/specifications/metric_fu-2.0.1.gemspec
shared/bundle/ruby/1.8/specifications/metric_fu-2.0.1.gemspec
&lt;span class='nv'&gt;$ &lt;/span&gt;ls /srv/my_app/shared/bundle/ruby/1.8/gems/metric_fu-2.0.1
HISTORY  lib  MIT-LICENSE  Rakefile  README  spec  tasks  TODO
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Fortunately this is really simple to fix, we just need to change our &lt;code&gt;Gemfile&lt;/code&gt; and move &lt;code&gt;metric_fu&lt;/code&gt; into the &lt;code&gt;test&lt;/code&gt; group&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;group&lt;/span&gt; &lt;span class='ss'&gt;:test&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;gem&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;metric_fu&amp;#39;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;My advice it &lt;strong&gt;do not&lt;/strong&gt; create any gem groups that do not correspond to your Rails environments as that seems to be what the bundler-capistrano and bundler-rails integrations expect.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/Brt1kVcqIGw" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/07/18/how-bundler-groups-relate-to-the-rails-environment.html</feedburner:origLink></entry>
 
 <entry>
   <title>Backbone.js Makes Building JavaScript Applications Fun</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/DnP3CzdY3O0/backbone.js-makes-building-javascript-applications-fun.html" />
   <published>2011-02-11T00:00:00-08:00</published>
   <updated>2011-02-11T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2011/02/11/backbone.js-makes-building-javascript-applications-fun</id>
   <content type="html">&lt;p&gt;Like many developers I&amp;#8217;ve had a long, complicated relationship with Javascript. Especially with libraries like &lt;a href='http://jquery.com'&gt;jquery&lt;/a&gt; it&amp;#8217;s incredibly easy to add interesting behavior to your pages, but unless you&amp;#8217;re very careful its also likely that you&amp;#8217;ll end up with a mess of spaghetti javascript. I know as I&amp;#8217;ve gotten myself into that mess and abandoned many projects because they were just too hard to change. All this has changed with some of new libraries out there that help you write your javascript following the MVC pattern.&lt;/p&gt;

&lt;p&gt;Today I&amp;#8217;m going to talk about &lt;a href='http://documentcloud.github.com/backbone/'&gt;backbone.js&lt;/a&gt; and show how it helped me and two friends build a rich one-page application to understand an exception stack trace. Backbone.js describes itself as supplying structure to JavaScript-heavy applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.&lt;/p&gt;

&lt;p&gt;There are a number of &lt;a href='http://liquidmedia.ca/blog/2011/01/backbone-js-part-1/'&gt;tutorials&lt;/a&gt; and &lt;a href='http://documentcloud.github.com/backbone/#examples'&gt;examples&lt;/a&gt; available out there to get you started. The basic idea is to uses backbone.js to organize your code into models, views and controllers.&lt;/p&gt;

&lt;h2 id='what_is_codebuddy'&gt;What is CodeBuddy&lt;/h2&gt;

&lt;p&gt;&lt;a href='http://rubygems.org/gems/code_buddy'&gt;CodeBuddy&lt;/a&gt; is the application I&amp;#8217;ll describe. It helps you navigate an exception stack raised by your Rails app or any other stack you paste in. I worked on it with &lt;a href='http://patshaughnessy.net'&gt;Pat Shaughnessy&lt;/a&gt; and &lt;a href='http://www.flyingmachinestudios.com/'&gt;Daniel Higginbotham&lt;/a&gt; and Pat produced a super article describing &lt;a href='http://patshaughnessy.net/2010/12/13/codebuddy-see-your-ruby-stack-come-alive'&gt;what CodeBuddy is and how to use it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is some server-side code that replaces the Rails Show Exceptions page and syntax highlights a snippet of source code for each line in the stack but for this article I&amp;#8217;m going to ignore that and focus on the interactive page and the javascript behind it.&lt;/p&gt;

&lt;p&gt;Below is a picture showing a stack trace the background and the code snippet for the currently selected line in front. Now a picture is okay but to really get a sense of it I suggest you follow this link to &lt;a href='/examples/code_buddy' target='_blank'&gt;experience Code Buddy in action&lt;/a&gt; - try pressing ↑ or ↓ or double clicking a few lines in the stack then press &lt;code&gt;s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/examples/code_buddy/images/code_buddy_screenshot.png' alt='Code Buddy' /&gt;&lt;/p&gt;

&lt;p&gt;There&amp;#8217;s a lot going on here and if we had tried building this before discovering backbone.js we probably would have had created a mess - mixing javascript and html that quickly would have become hard to change. I&amp;#8217;m going to show you how backbone let us separate the models from the views and create something that was not hard to grow.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s get into the technical details!&lt;/p&gt;

&lt;h2 id='organizing_our_data_in_backbone_models'&gt;Organizing our data in Backbone Models&lt;/h2&gt;

&lt;p&gt;We want to follow good OO design principles and thinking about this our exception stack is really just a few objects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A &lt;code&gt;Stack&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;has many &lt;code&gt;Addresses&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;knows which &lt;code&gt;Address&lt;/code&gt; is selected&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Each &lt;code&gt;Address&lt;/code&gt; has&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;path to a file&lt;/li&gt;

&lt;li&gt;line number&lt;/li&gt;

&lt;li&gt;snippet of code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can build this as a JSON object like&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;stackJson&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;stack_frames&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/Users/alex/ruby/github/test_app/app/controllers/users_controller.rb&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;line&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;class UsersController &amp;lt; ApplicationController\n...&amp;quot;&lt;/span&gt;
    &lt;span class='p'&gt;},&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/Users/alex/.rvm/.../lib/action_controller/metal/implicit_render.rb&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;line&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;module ActionController\n...&amp;quot;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='p'&gt;],&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;selected&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The first step is to turn this into backbone models.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='c1'&gt;// Stack, Address and Addresses&lt;/span&gt;
&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Stack&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Model&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;extend&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;
  &lt;span class='nx'&gt;initialize&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;set&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;
      &lt;span class='nx'&gt;addresses&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Addresses&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;stack_frames&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; 
    &lt;span class='p'&gt;})&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;})&lt;/span&gt;

&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Address&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Model&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;extend&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;
&lt;span class='p'&gt;})&lt;/span&gt;

&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Addresses&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Collection&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;extend&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;
  &lt;span class='nx'&gt;model&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Address&lt;/span&gt;
&lt;span class='p'&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The way we build a model in backbone is by extending &lt;code&gt;Backbone.Model&lt;/code&gt;. When extending we can add custom behavior if we want. In our example we tell the &lt;code&gt;Stack&lt;/code&gt; to contain a collection of &lt;code&gt;Address&lt;/code&gt; objects in the &lt;code&gt;Addresses&lt;/code&gt; collection. We use the backbone collection framework to define &lt;code&gt;Addresses&lt;/code&gt; and tell it that it is a collection of &lt;code&gt;Address&lt;/code&gt; model objects. These models will use the default backbone behavior for the rest which includes read/write access to its properties &lt;code&gt;get&lt;/code&gt; or &lt;code&gt;set&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now that they&amp;#8217;re defined, we&amp;#8217;re ready to interact with these models. For example below is what you&amp;#8217;d see using the Chrome javascript console (I&amp;#8217;m showing the output as comments for readability)&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='c1'&gt;// Using our models in a console&lt;/span&gt;
&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;stack&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Stack&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;stack_frames&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/Users/alex/ruby/github/test_app/app/controllers/users_controller.rb&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;line&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;class UsersController &amp;lt; ApplicationController\n...&amp;quot;&lt;/span&gt;
    &lt;span class='p'&gt;},&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/Users/alex/.rvm/.../lib/action_controller/metal/implicit_render.rb&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;line&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='s2'&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;module ActionController\n...&amp;quot;&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='p'&gt;],&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;selected&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;
&lt;span class='p'&gt;})&lt;/span&gt;
&lt;span class='c1'&gt;// inherits.child&lt;/span&gt;

&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;stack&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;addresses&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c1'&gt;// inherits.child&lt;/span&gt;

&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;stack&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;addresses&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;first&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c1'&gt;// &amp;quot;/Users/alex/ruby/github/test_app/app/controllers/users_controller.rb&amp;quot;&lt;/span&gt;

&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;stack&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;addresses&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;first&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;code&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='c1'&gt;// &amp;quot;class UsersController &amp;lt; ApplicationController&lt;/span&gt;
&lt;span class='c1'&gt;// ...&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;We now have an object hierarchy with default behavior which we can (and will) extend in a bit but first let&amp;#8217;s build some views and get a page we can look at.&lt;/p&gt;

&lt;h2 id='building_the_ui_with_backbone_views'&gt;Building the UI with Backbone Views&lt;/h2&gt;

&lt;p&gt;We&amp;#8217;re going to build&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;StackView&lt;/code&gt; that contains many &lt;code&gt;AddressViews&lt;/code&gt;&lt;/li&gt;

&lt;li&gt;Each &lt;code&gt;AddressView&lt;/code&gt; will display a single line from the stack.&lt;/li&gt;

&lt;li&gt;Each view will be tied to one of our model objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It will look something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/examples/code_buddy/images/annotated_screenshot.png' alt='Code Buddy views on the page' /&gt;&lt;/p&gt;

&lt;p&gt;We can start with a &lt;code&gt;StackView&lt;/code&gt; that&amp;#8217;s tied to the &lt;code&gt;Stack&lt;/code&gt; model. Creating a backbone view is very similar to how we created our models - we extend &lt;code&gt;Backbone.View&lt;/code&gt; and can override behavior if we want.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;StackView&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;View&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;extend&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;

  &lt;span class='nx'&gt;el&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;#stack&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;

  &lt;span class='nx'&gt;initialize&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;model&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;addresses&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;each&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;addOneAddress&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;},&lt;/span&gt;
  
  &lt;span class='nx'&gt;addOneAddress&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;address&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;index&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;view&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;AddressView&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;&lt;span class='nx'&gt;model&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='nx'&gt;address&lt;/span&gt;&lt;span class='p'&gt;});&lt;/span&gt;
    &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;#stack&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;append&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;view&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;render&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;el&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;In this case we overrode the &lt;code&gt;initializer&lt;/code&gt; function to create an &lt;code&gt;AddressView&lt;/code&gt; for each address. It also uses jQuery to add the &lt;code&gt;AddressView&amp;#39;s&lt;/code&gt; html within the page&amp;#8217;s &lt;code&gt;#stack&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;To do the iteration we use another powerful javascript library called &lt;a href='http://documentcloud.github.com/underscore/'&gt;underscore.js&lt;/a&gt;. Underscore.js gives us a ruby-like collection methods letting us write &lt;code&gt;.each(this.addOneAddress)&lt;/code&gt;. This will iterate over all the &lt;code&gt;addressses&lt;/code&gt; calling the &lt;code&gt;addOneAddress&lt;/code&gt; function on each one. Underscore.js also gives us erb-like templating we&amp;#8217;ll use in the &lt;code&gt;AddressView&lt;/code&gt;&amp;#8230;let&amp;#8217;s take a look at that view.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;AddressView&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;View&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;extend&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;
  &lt;span class='nx'&gt;tagName&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;  &lt;span class='s2'&gt;&amp;quot;li&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;

  &lt;span class='nx'&gt;template&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='nx'&gt;_&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;template&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;span class=&amp;#39;container&amp;#39;&amp;gt;&amp;lt;%= path %&amp;gt;:&amp;lt;%= line%&amp;gt;&amp;lt;/span&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;

  &lt;span class='nx'&gt;initialize&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='p'&gt;},&lt;/span&gt;

  &lt;span class='nx'&gt;render&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;html&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;template&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;model&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;toJSON&lt;/span&gt;&lt;span class='p'&gt;())&lt;/span&gt;
    &lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;el&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;html&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;html&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You can see the template and how it does look like erb. It defines the html that will be displayed for each address and its able to access properties in the model like &lt;code&gt;path&lt;/code&gt; and &lt;code&gt;line&lt;/code&gt;. The template gets applied in the &lt;code&gt;render&lt;/code&gt; function with the line &lt;code&gt;this.template(this.model.toJSON())&lt;/code&gt;. Finally, &lt;code&gt;tagName&lt;/code&gt; is used to wrap this html in an &lt;code&gt;li&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;Now we can put it all together to see on a page. We can start with a toplevel page that has an element with &lt;code&gt;stack&lt;/code&gt;, includes our models and views and tells them to load.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='html'&gt;&lt;span class='nt'&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;ul&lt;/span&gt; &lt;span class='na'&gt;id=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;stack&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;script &lt;/span&gt;&lt;span class='na'&gt;src=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;javascripts/code_buddy.js&amp;quot;&lt;/span&gt; &lt;span class='na'&gt;type=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;setup&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;stack_frames&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;
          &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/Users/alex/ruby/github/test_app/app/controllers/users_controller.rb&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;line&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;class UsersController &amp;lt; ApplicationController\n...&amp;quot;&lt;/span&gt;
          &lt;span class='p'&gt;},&lt;/span&gt;
          &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;/Users/alex/.rvm/.../lib/action_controller/metal/implicit_render.rb&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;line&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
            &lt;span class='s2'&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;module ActionController\n...&amp;quot;&lt;/span&gt;
          &lt;span class='p'&gt;}&lt;/span&gt;
        &lt;span class='p'&gt;],&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;selected&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;
      &lt;span class='p'&gt;})&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;After the page loads and the views render it changes the &lt;code&gt;#stack&lt;/code&gt; div to have all this&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='html'&gt;&lt;span class='nt'&gt;&amp;lt;ul&lt;/span&gt; &lt;span class='na'&gt;id=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;stack&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;span&lt;/span&gt; &lt;span class='na'&gt;class=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;container&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;/Users/alex/ruby/github/test_app/app/controllers/users_controller.rb:5&lt;span class='nt'&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;span&lt;/span&gt; &lt;span class='na'&gt;class=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;container&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;/Users/alex/.rvm/.../lib/action_controller/metal/implicit_render.rb:4&lt;span class='nt'&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;So far this is a lot of framework and structure for a simple page but now is when it gets interesting and backbone reveals its true power!&lt;/p&gt;

&lt;h2 id='showing_code_for_the_selected_address'&gt;Showing code for the selected address&lt;/h2&gt;

&lt;p&gt;Let&amp;#8217;s say we want to mark one address selected and show the code for that one.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://www.alexrothenberg.com/examples/code_buddy/images/code_buddy_screenshot_with_selection.png' alt='Showing Code for selected Addresss' /&gt;&lt;/p&gt;

&lt;p&gt;We can start by adding an element to the html called &lt;code&gt;code-viewer&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='html'&gt;&lt;span class='nt'&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;ul&lt;/span&gt; &lt;span class='na'&gt;id=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;stack&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;div&lt;/span&gt; &lt;span class='na'&gt;id=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;code-viewer&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&lt;/span&gt;
    &lt;span class='nt'&gt;&amp;lt;div&lt;/span&gt; &lt;span class='na'&gt;id=&lt;/span&gt;&lt;span class='s'&gt;&amp;quot;code&amp;quot;&lt;/span&gt;&lt;span class='nt'&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class='nt'&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class='c'&gt;&amp;lt;!-- all the javascript omitted for clarity --&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class='nt'&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we want to create a &lt;code&gt;StackView&lt;/code&gt; to put the right code in there&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;CodeView&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;View&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;extend&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;
  &lt;span class='nx'&gt;el&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;&lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;#code-viewer&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
  
  &lt;span class='nx'&gt;initialize&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='p'&gt;},&lt;/span&gt;
  
  &lt;span class='nx'&gt;render&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;#code&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;html&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;stack&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;selectedAddress&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;code&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;In this view we used our models to find which address was selected &lt;code&gt;CodeBuddy.stack.selectedAddress()&lt;/code&gt; so let&amp;#8217;s add that method.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Stack&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Model&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;extend&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;
  &lt;span class='nx'&gt;initialize&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='c1'&gt;// same code as before&lt;/span&gt;
  &lt;span class='p'&gt;},&lt;/span&gt;

  &lt;span class='nx'&gt;addresses&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;addresses&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;},&lt;/span&gt;

  &lt;span class='nx'&gt;selectedAddress&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;selected&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;selected&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;addresses&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;at&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;selected&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;That&amp;#8217;s it, now we have a code view on top of the stack view and our code is still clean and well organized. I&amp;#8217;m not afraid to keep going and make our next change.&lt;/p&gt;

&lt;h2 id='changing_the_selected_address'&gt;Changing the selected address&lt;/h2&gt;

&lt;p&gt;Oh, we just got a new requirement to be able to scroll up and down through the stack and see the code window change as we go.&lt;/p&gt;

&lt;p&gt;We add some more functions to our Stack Model so we can change the selection and we also tell it to call the &lt;code&gt;selectionChanged&lt;/code&gt; function whenever the &lt;code&gt;selected&lt;/code&gt; property changes. Calling a function on a property change is something that&amp;#8217;s given to us with &lt;a href='http://documentcloud.github.com/backbone/#Events'&gt;backbone events&lt;/a&gt;. Getting the view to update itself is also easy we just tell it to with &lt;code&gt;CodeBuddy.codeView.render()&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Stack&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;Backbone&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;Model&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;extend&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;
  &lt;span class='nx'&gt;initialize&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;bind&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;change:selected&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;selectionChanged&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='c1'&gt;// same code as before&lt;/span&gt;
  &lt;span class='p'&gt;},&lt;/span&gt;

  &lt;span class='nx'&gt;setSelection&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;newSelected&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;newSelected&lt;/span&gt; &lt;span class='o'&gt;&amp;gt;=&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='nx'&gt;newSelected&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;addresses&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;size&lt;/span&gt;&lt;span class='p'&gt;())&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;set&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt; &lt;span class='nx'&gt;selected&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='nx'&gt;newSelected&lt;/span&gt; &lt;span class='p'&gt;})&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='p'&gt;},&lt;/span&gt;
  
  &lt;span class='nx'&gt;selectPrevious&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;setSelection&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;selected&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;},&lt;/span&gt;
  
  &lt;span class='nx'&gt;selectNext&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;setSelection&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;selected&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='p'&gt;},&lt;/span&gt; 

  &lt;span class='nx'&gt;selectionChanged&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;x&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;addresses&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;at&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;x&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;previousAttributes&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;selected&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;view&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;render&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;addresses&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;at&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;x&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;changedAttributes&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;selected&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;view&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;render&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;codeView&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;render&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
  &lt;span class='p'&gt;},&lt;/span&gt;
  
  &lt;span class='c1'&gt;// all the existing functions remain  &lt;/span&gt;
&lt;span class='p'&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The last thing we need to do is give some way for the user to change the selection. We decided to use &lt;a href='http://code.google.com/p/js-hotkeys/'&gt;jQuery Hotkeys&lt;/a&gt; to bind to the up and down arrows (↑ or ↓).&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;setStackKeyBindings&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(){&lt;/span&gt;
  &lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;document&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;bind&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;keydown&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;up&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;   &lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;stack&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;selectPrevious&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;document&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;bind&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;keydown&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;down&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;CodeBuddy&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;stack&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;selectNext&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='conclusion'&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I hope this example has shown a little of the power of using backbone.js when you need to write a complex javascript application.&lt;br /&gt;If you want to see the actual application its all on Github in &lt;a href='https://github.com/patshaughnessy/code_buddy/blob/master/lib/code_buddy/public/javascripts/code_buddy.js'&gt;code_buddy.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was our first project working with backbone.js and I&amp;#8217;m sure there&amp;#8217;s much more we can learn but we&amp;#8217;ve found that it lets us write modular code with many small methods which feels much closer to writing Ruby than my previous forays into javascript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backbone.js makes writing a javascript application fun!&lt;/strong&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/DnP3CzdY3O0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/02/11/backbone.js-makes-building-javascript-applications-fun.html</feedburner:origLink></entry>
 
 <entry>
   <title>Moved Blog to Jekyll and GitHub Pages</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/fHnz9m506h4/moved-blog-to-jekyll-and-github-pages.html" />
   <published>2011-01-27T00:00:00-08:00</published>
   <updated>2011-01-27T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2011/01/27/moved-blog-to-jekyll-and-github-pages</id>
   <content type="html">&lt;p&gt;I just moved my blog to &lt;a href='http://jekyllrb.com'&gt;Jekyll&lt;/a&gt; and &lt;a href='http://pages.github.com'&gt;Github Pages&lt;/a&gt; which I hope will help me get back into the rhythm of posting regularly.&lt;/p&gt;

&lt;h2 id='why_did_i_switch'&gt;Why did I switch?&lt;/h2&gt;

&lt;p&gt;There were several things I wanted to change&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Syntax highlighting for my code&lt;/em&gt; &amp;#8212; Jekyll uses &lt;a href='http://pygments.org/'&gt;pygments&lt;/a&gt; which supports about a bazillion &lt;a href='http://pygments.org/languages/'&gt;languages&lt;/a&gt; including &amp;#8220;Gherkin&amp;#8221; (cucumber) and blogger had nothing.&lt;/li&gt;

&lt;li&gt;&lt;em&gt;Authoring tools I wanted&lt;/em&gt; &amp;#8212; The blogger wysiwyg editor never really worked for me and I&amp;#8217;d prefer to use &lt;a href='http://macromates.com'&gt;TextMate&lt;/a&gt; and &lt;a href='http://en.wikipedia.org/wiki/Markdown'&gt;markdown&lt;/a&gt; or &lt;a href='http://en.wikipedia.org/wiki/Textile_%28markup_language%29'&gt;textile&lt;/a&gt; anyway.&lt;/li&gt;

&lt;li&gt;&lt;em&gt;New site design&lt;/em&gt; &amp;#8212; Making the move gave me a chance to redo my design. The old one felt cluttered and dated and I hope this new one is not.&lt;/li&gt;

&lt;li&gt;&lt;em&gt;Geek street cred&lt;/em&gt; &amp;#8212; I like having everything on &lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com'&gt;github&lt;/a&gt; and besides all the cool kids are doing it :)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Jekyll&lt;/em&gt; is a gem that converts a structured directory of pages and posts written in markdown, textile or html into static html files that can be served by apache or nginx. Of course there&amp;#8217;s an &lt;a href='https://github.com/mojombo/jekyll/wiki'&gt;official definition&lt;/a&gt; that explains it in more detail.&lt;/p&gt;

&lt;p&gt;With &lt;em&gt;Github Pages&lt;/em&gt; I just have to create a git repository &lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com'&gt;alexrothenberg.github.com&lt;/a&gt; and with each push github runs jekyll to generate a static site it serves up at &lt;a href='http://alexrothenberg.github.com'&gt;http://alexrothenberg.github.com&lt;/a&gt;&lt;/p&gt;

&lt;h2 id='how_did_i_create_this_new_site'&gt;How did I create this new site?&lt;/h2&gt;

&lt;h3 id='1_create_an_empty_site'&gt;1. Create an empty site&lt;/h3&gt;

&lt;p&gt;There are lots of &lt;a href='https://github.com/mojombo/jekyll/wiki/Sites'&gt;sites&lt;/a&gt; others have created with jekyll to peruse for design ideas. I spent some time looking through them and eventually picked one to use as a template. I copied one and pushed it to a new project on github called &lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com'&gt;alexrothenberg.github.com&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id='2_get_my_existing_content'&gt;2. Get my existing content&lt;/h3&gt;

&lt;p&gt;First I had to get my old content out of blogger into a Jekyll site. There are instructions for &lt;a href='https://github.com/mojombo/jekyll/wiki/Blog-Migrations'&gt;migrating&lt;/a&gt; from many different platforms (including &lt;a href='http://coolaj86.info/articles/migrate-from-blogger-to-jekyll.html'&gt;from blogger to jekyll&lt;/a&gt;). I followed the instructions to &amp;#8220;import with vilcans&amp;#8217; Jekyll rss_importer&amp;#8221; and just had to change the rss url to http://www.alexrothenberg.com/feeds/posts/full?alt=rss&amp;amp;max-results=1000 since I had more than 25 posts.&lt;/p&gt;

&lt;p&gt;I now had my posts in the &lt;em&gt;_posts&lt;/em&gt; folder. I copied these posts into my &lt;em&gt;alexrothenberg.github.com/_posts&lt;/em&gt; and had a version of my blog with all my old posts.&lt;/p&gt;

&lt;h3 id='3_syntax_highlighting_code'&gt;3. Syntax highlighting code&lt;/h3&gt;

&lt;p&gt;I next did some experimentation with the old posts to see how the code highlighting worked. It&amp;#8217;s very natural and in-the-flow.&lt;/p&gt;

&lt;p&gt;While writing my article I just add a block like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{ % highlight ruby %}
class User
  def name
    [first, last].join(&amp;#39; &amp;#39;) 
  end
end
{ % endhighlight %}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and get this fantastic output&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;User&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;name&lt;/span&gt;
    &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;last&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; 
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Well not quite&amp;#8230; It generated html with all sorts of css classes but I couldn&amp;#8217;t find css stylesheets out there with the &lt;a href='http://alternateidea.com/blog/articles/2006/01/03/textmate-vibrant-ink-theme-and-prototype-bundle'&gt;Vibrant Ink&lt;/a&gt; theme I like.&lt;br /&gt;Through some trial and error I created my own &lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com/blob/master/stylesheets/vibrant_ink.css'&gt;vibrant_ink.css&lt;/a&gt;&lt;/p&gt;

&lt;h3 id='4_disqus_comments'&gt;4. Disqus comments&lt;/h3&gt;

&lt;p&gt;Because Jekyll generates static pages it has no commenting engine so I have to integrate with an external service. I decided to go with &lt;a href='http://disqus.com'&gt;disqus&lt;/a&gt;.&lt;br /&gt;Adding it into my site was simple but getting my old comments in turned out to be much harder than it should have been.&lt;/p&gt;

&lt;p&gt;First I went to disqus.com, signed up for an account and used their admin too to create a site for www.alexrothenberg.com. They give you a bit of javascript to add to your page. I added this to my &lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com/blob/master/_layouts/post.html#L12-14'&gt;_layouts/post.html&lt;/a&gt; and I was done.&lt;/p&gt;

&lt;p&gt;It looked like it would be just as easy to import my comments from blogger as they have a big &lt;em&gt;import from blogger&lt;/em&gt; button on their admin site under Tools-&amp;gt;Import/Export. I ran it and I suddenly had all my old comments. But this is where things started to break down. Blogger ties the comments to &lt;a href='http://www.blogger.com/profile/18273757675203348828'&gt;blogger profiles&lt;/a&gt; instead of an email address so none of my comments had avatar pictures next to them.&lt;/p&gt;

&lt;p&gt;What followed was a frustrating journey to try and edit the comments using their admin tool. The first thing I tried was using their admin tool but it doesn&amp;#8217;t let you edit a commenter&amp;#8217;s email or url so I couldn&amp;#8217;t stick email addresses in when I knew them (for example I know my own email). My next approach was to export the comments in disqus, edit the xml file it gave me and re-upload. The problem here is that the exported xml uses a different format than the import accepts although they don&amp;#8217;t tell you that when you try importing the file you exported it just tells you 0 items imported - how annoying?!?&lt;/p&gt;

&lt;p&gt;After a lot of trial and error I wound up with all my comments in an xml file that disqus could import. In case you want to do something similar here are the steps I followed&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a temp site in disqus (I called mine alexrothenberg1)&lt;/li&gt;

&lt;li&gt;Import the comments from blogger using the Disqus import tool&lt;/li&gt;

&lt;li&gt;Export those comments to an xml file - I saved mine in &lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com/blob/master/_disqus_import/exported_comments.xml'&gt;alexrothenberg.github.com/_disqus_import/exported_comments.xml&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;Run my script &lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com/blob/master/_disqus_import/export2import'&gt;alexrothenberg.github.com/_disqus_import/exported2import&lt;/a&gt; to migrate the format to a Word Press XFR and change the timestamp format.&lt;/li&gt;

&lt;li&gt;Hand edit &lt;br /&gt;&lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com/blob/master/_disqus_import/import_comments.xml'&gt;alexrothenberg.github.com/_disqus_import/import_comments.xml&lt;/a&gt; to update the emails and urls for each comment (luckily I didn&amp;#8217;t have that many old comments)&lt;/li&gt;

&lt;li&gt;Delete the temp discus site and create a new one&lt;/li&gt;

&lt;li&gt;Import my XFR file to the new site&lt;/li&gt;

&lt;li&gt;Jekyll and Blogger use different formats for post urls (jekyll includes year/month/date while blogger is year/month) so we need to run the disqus Migrate Threads-&amp;gt;Upload a URL Map tool to upload a file like &lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com/blob/master/_disqus_import/url.map'&gt;alexrothenberg.github.com/_disqus_import/url.map&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id='5_mapping_my_domain_name'&gt;5. Mapping my domain name&lt;/h3&gt;

&lt;p&gt;At this point I have a blog site up at http://alexrothenberg.github.com and its only a quick step to start serving it at &lt;a href='http://www.alexrothenberg.com'&gt;http://www.alexrothenberg.com&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com/blob/master/CNAME'&gt;CNAME&lt;/a&gt; containing &lt;code&gt;www.alexrothenberg.com&lt;/code&gt; in my project&lt;/li&gt;

&lt;li&gt;Update the dns entry in my domain to create a CNAME record aliasing &lt;code&gt;www&lt;/code&gt; to &lt;code&gt;alexrothenberg.github.com&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id='authoring_and_publishing'&gt;Authoring and Publishing&lt;/h2&gt;

&lt;p&gt;Now that the site is up and running it was time to write my first article (this one).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;jekyll --auto --server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Starts the jekyll server running at http://localhost:4000 and monitors the files so it regenerates each time I save an edit&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;code&gt;newpost Moved Blog to Jekyll and GitHub Pages&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Creates a new empty post using a script I stuck in my project &lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com/blob/master/_bin/newpost'&gt;_bin&lt;/a&gt; (thanks &lt;a href='https://github.com/al3x'&gt;al3x&lt;/a&gt; for this &lt;a href='https://gist.github.com/100171/26dfa6f55f442c223c8491fb2bfaea15bda7351a'&gt;gist&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Start writing content in &lt;a href='https://github.com/alexrothenberg/alexrothenberg.github.com/blob/master/_posts/2011-01-27-moved-blog-to-jekyll-and-github-pages.md'&gt;_posts/2011-01-27-moved-blog-to-jekyll-and-github-pages.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each time I hit save I can preview in a few seconds at http://localhost:4000&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;code&gt;git commit -am &amp;#39;wrote the article&amp;#39;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;code&gt;git push origin master&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In a few seconds github processes the site into static files and its published for all the world to see.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/fHnz9m506h4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/01/27/moved-blog-to-jekyll-and-github-pages.html</feedburner:origLink></entry>
 
 <entry>
   <title>Setting up a new Mac for Rails Development</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/6lXvvkIXaB0/setting-up-new-mac-for-rails.html" />
   <published>2011-01-04T00:00:00-08:00</published>
   <updated>2011-01-04T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2011/01/04/setting-up-new-mac-for-rails</id>
   <content type="html">&lt;p&gt;
  I just got a new MacBook (whoo hoo!) because my old machine dies (boo hoo) and thought I'd write down the steps I'm taking to set it up. I imagine this is more for myself than anyone else but keep reading if you like.
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Some Apps
    &lt;ol&gt;
      &lt;li&gt;&lt;a href="http://www.google.com/chrome"&gt;Google Chrome&lt;/a&gt; for browsing&lt;/li&gt;
      &lt;li&gt;&lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt; for editing&lt;/li&gt;
      &lt;li&gt;&lt;a href="http://adium.im/"&gt;Adium&lt;/a&gt; for IM&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;

  &lt;br/&gt;
  &lt;li&gt;Homebrew for package management
    &lt;ol&gt;
      &lt;li&gt;Open a terminal and type&lt;br&gt;
        &lt;pre class="old_code"&gt;
ruby -e "$(curl -fsSL https://gist.github.com/raw/323731/install_homebrew.rb)
&lt;/pre&gt;
      &lt;/li&gt;
      &lt;li&gt;Download and Install &lt;a href="http://developer.apple.com/technologies/xcode.html"&gt;XCode&lt;/a&gt; from Apple
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;

  &lt;br/&gt;
  &lt;li&gt;git &amp;amp; github for development
    &lt;ol&gt;
      &lt;li&gt;Install GIT&lt;br&gt;
        &lt;pre class="old_code"&gt;
brew install git
&lt;/pre&gt;
      &lt;/li&gt;
      &lt;li&gt;create ssh keys and add to github following &lt;a href="http://help.github.com/mac-key-setup/"&gt;these instructions&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;Configure git&lt;br&gt;
        &lt;pre class="old_code"&gt;
git config --global user.name "Alex Rothenberg"&lt;br&gt;git config --global user.email "alex@alexrothenberg.com"&lt;br&gt;git config --global color.ui true
&lt;/pre&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;

  &lt;br/&gt;
  &lt;li&gt;RVM
    &lt;ol&gt;
      &lt;li&gt;
        &lt;a href="http://rvm.beginrescueend.com/rvm/install/"&gt;Install rvm&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;add bundler to ~/.rvm/gemsets/global.gems and install it&lt;br&gt;
        &lt;pre class="old_code"&gt;
echo bundler &amp;gt;&amp;gt; ~/.rvm/gemsets/global.gems&lt;br&gt;gem install bundler&lt;br&gt;
&lt;/pre&gt;
      &lt;/li&gt;
      &lt;li&gt;install Ruby 1.8.7 and make it default&lt;br&gt;
        &lt;pre class="old_code"&gt;
rvm install 1.8.7&lt;br&gt;rvm --default 1.8.7
&lt;/pre&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;

  &lt;br/&gt;
  &lt;li&gt;Databases
    &lt;ol&gt;
      &lt;li&gt;MySQL&lt;br&gt;
        &lt;pre class="old_code"&gt;
brew install mysql
&lt;/pre&gt;
      &lt;/li&gt;
      &lt;li&gt;Oracle (this is complicated but works if you follow the directions &lt;b&gt;exactly&lt;/b&gt; TO THE LETTER without missing a single step!) &lt;a href="http://blog.rayapps.com/2009/09/14/how-to-install-oracle-database-10g-on-mac-os-x-snow-leopard/"&gt;http://blog.rayapps.com/2009/09/14/how-to-install-oracle-database-10g-on-mac-os-x-snow-leopard/&lt;/a&gt;. Then I did have to run these extra commands&lt;br&gt;
        &lt;ol&gt;
          &lt;li&gt;Add oracle env settings to my user&lt;br&gt;
            &lt;pre class="old_code"&gt;
#.bashrc&lt;br&gt;## ORACLE &lt;br&gt;export ORACLE_HOME=/Users/oracle/oracle/product/10.2.0/db_1&lt;br&gt;export DYLD_LIBRARY_PATH=$ORACLE_HOME/lib&lt;br&gt;export ORACLE_SID=orcl&lt;br&gt;PATH=$PATH:$ORACLE_HOME/bin
&lt;/pre&gt;&lt;br&gt;
          &lt;/li&gt;
          &lt;li&gt;Enable me to access the oracle files&lt;br&gt;
            &lt;pre class="old_code"&gt;
sudo dscl localhost -append /Local/Default/Groups/oinstall GroupMembership alex
&lt;/pre&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;a href="http://www.oracle.com/technetwork/developer-tools/sql-developer/overview/index.html"&gt;SQL Developer&lt;/a&gt; is an Oracle GUI
          &lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;

  &lt;br/&gt;
  &lt;li&gt;Test with a project
    &lt;br/&gt;
    &lt;pre class="old_code"&gt;
git clone git://github.com/alexrothenberg/legacy_data.git
cd legacy_data
export MYSQL
export ORACLE
bundle install
rake
&lt;/pre&gt;
  &lt;/li&gt;

  &lt;br/&gt;
  &lt;li&gt;Finally I'm following the trend and setting up a &lt;a href="https://github.com/alexrothenberg/dotfiles"&gt;dotfiles&lt;/a&gt; project on github so I don't have to recreate them in the future.&lt;br&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/6lXvvkIXaB0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2011/01/04/setting-up-new-mac-for-rails.html</feedburner:origLink></entry>
 
 <entry>
   <title>Combining two related fields in a url to prevent tampering</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/wwdC6E6qocY/combining-two-related-fields-in-url-to.html" />
   <published>2010-10-11T00:00:00-07:00</published>
   <updated>2010-10-11T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2010/10/11/combining-two-related-fields-in-url-to</id>
   <content type="html">&lt;p&gt;
  Usually when you select an item from a search results list you only need to pass the &lt;span style="font-style:italic;"&gt;id&lt;/span&gt; in the url and that's enough to lookup the rest of the details when processing the response. Recently I had a case where I couldn't lookup the item from the id because it wasn't in my database. I'm going to describe how I passed several pieces of information in a single url and what I did to ensure users could not be manipulate them independently.&lt;br&gt;
  &lt;br&gt;
  My application was searching and displaying a list of companies then keeping track of which one the user selects.&lt;br&gt;
  &lt;br&gt;
  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_36rptmL_RFc/TKsmV5B4vYI/AAAAAAAAD2A/Wf9a6OI-4kY/s1600/company_search_results.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 147px;" src="http://1.bp.blogspot.com/_36rptmL_RFc/TKsmV5B4vYI/AAAAAAAAD2A/Wf9a6OI-4kY/s320/company_search_results.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5524551525427887490" name="BLOGGER_PHOTO_ID_5524551525427887490"&gt;&lt;/a&gt;&lt;br&gt;
  &lt;br&gt;
  When someone clicks on a company name it would save the company's id and display a nice message "Thanks for selecting Google Inc." Since the companies came from a slow external service I didn't want to call again, I passed both the &lt;span style="font-style:italic;"&gt;id&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;name&lt;/span&gt; in the url.&lt;br&gt;
  &lt;br&gt;
  I built a couple of simple &lt;a href="http://haml-lang.com/"&gt;haml&lt;/a&gt; files to show my company list. Each row had a link to display the company name and passed both the name and id in the url.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;# search_results.html.haml&lt;/span&gt;
&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;
  &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;tr&lt;/span&gt;
    &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt; &lt;span class="no"&gt;Company&lt;/span&gt; &lt;span class="no"&gt;Name&lt;/span&gt;
    &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt; &lt;span class="no"&gt;Location&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="vi"&gt;@companies&lt;/span&gt;


&lt;span class="c1"&gt;# _company.html.haml partial&lt;/span&gt;
&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;tr&lt;/span&gt;
  &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;company_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  The controller code was also pretty straightforward.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CompaniesController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
    &lt;span class="n"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Company&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_selected_company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;company&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  This worked great and worked, but then we started looking at the urls in our browser and noticed they looked like &lt;code&gt;http://my.site.com/companies/60902413&amp;amp;name=Google+Inc.&lt;/code&gt;.&lt;br&gt;
  &lt;br&gt;
  Hmm ... What would happen if someone changed the name in the url? We tried loading &lt;code&gt;http://my.site.com/companies/60902413&amp;amp;name=Some+Silly+Name&lt;/code&gt;. Uh-oh, our database now stored the selected company &lt;span style="font-style:italic;"&gt;Some Silly Name&lt;/span&gt; with id #60902413. This could be confusing or worse a security risk where a clever (or malicious) user could store inaccurate information in our database.&lt;br&gt;
  &lt;br&gt;
  Our solution was to combine the two fields into a single query parameter that was resistant to user tampering and is passed as a single unit. Fortunately Rails passes the session back and forth in a cookie with just that requirement. The session is a hash of many different key-value pairs that need to be encoded as a single cookie, it also contains sensitive information that should be resistant to tampering (and unreadable) and, most importantly it turns out to be something we could reuse.&lt;br&gt;
  &lt;br&gt;
  Starting from the outside in what we wanted to do was rewrite our &lt;code&gt;_company.html.haml&lt;/code&gt; partial view to put the single encrypted form of the company on the url.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;tr&lt;/span&gt;
  &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;company_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_encrypted_s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;td&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  and parse that in the controller
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CompaniesController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;action&lt;/span&gt;
    &lt;span class="n"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Company&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_encrypted_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_selected_company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;company&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Ok, but what do those &lt;span style="font-style:italic;"&gt;to_encrypted_s&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;from_encrypted_s&lt;/span&gt; methods do?&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Company&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_encrypted_s&lt;/span&gt;
    &lt;span class="no"&gt;Encryption&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:company_name&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;company_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:duns&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;duns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_encrypted_s&lt;/span&gt; &lt;span class="n"&gt;encrypted_data&lt;/span&gt;
    &lt;span class="no"&gt;Company&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="no"&gt;Encryption&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  I still haven't told you how they work, we're just working down from the outside-in figuring out what other classes we'll need. So what does the &lt;span style="font-style:italic;"&gt;Encryption&lt;/span&gt; class look like?
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Encryption&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
    &lt;span class="n"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;3.0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
             &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cookie_secret&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; 
             &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_options&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:secret&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="vi"&gt;@verifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;MessageVerifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SHA1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;encrypt&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;
    &lt;span class="vi"&gt;@verifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decrypt&lt;/span&gt; &lt;span class="n"&gt;encrypted&lt;/span&gt;
    &lt;span class="vi"&gt;@verifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt; &lt;span class="n"&gt;encrypted&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  We make use of the &lt;a href="http://api.rubyonrails.org/classes/ActiveSupport/MessageVerifier.html"&gt;ActiveSupport::MessageVerifier&lt;/a&gt; class which as the documentation says "makes it easy to generate and verify messages which are signed to prevent tampering".&lt;br&gt;
  &lt;br&gt;
  Now when we select a company we get a url with a crazy long id like http://my.site.com/company/BAh7BzoJZHVuc2kDE%2BAUOhFjb21wYW55X25hbWUiMEludGVybmF0aW9uYWwgQnVzaW5lc3MgTWFjaGluZXMgQ29ycG9yYXRpb24%3D--9027b2c449c0b4a1aea375cb1722fa9db8e56066. If someone were to try and change the really long id in the url the application will throw an &lt;span style="font-style:italic;"&gt;ActiveSupport::MessageVerifier::InvalidSignature&lt;/span&gt; exception instead of saving bad data.&lt;br&gt;
  &lt;br&gt;
  We've given up readability in the url but in exchange we're guaranteed the id and name we get in the controller go with each other.
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/wwdC6E6qocY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2010/10/11/combining-two-related-fields-in-url-to.html</feedburner:origLink></entry>
 
 <entry>
   <title>Purging old cruise builds</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/BQX2mnSXwE4/purging-old-cruise-builds.html" />
   <published>2010-09-29T00:00:00-07:00</published>
   <updated>2010-09-29T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2010/09/29/purging-old-cruise-builds</id>
   <content type="html">Continuous Integration is such an important idea and I love &lt;a href="http://cruisecontrolrb.thoughtworks.com/"&gt;CruiseControl.rb&lt;/a&gt; as its so easy to use.  However one thing that drives me crazy is that it keeps all builds &lt;span style="font-style:italic;"&gt;forever&lt;/span&gt;.  Over the past few years we run out of disk space every few months causing all our builds to start failing and some tedious manual work to delete some directories.  &lt;br /&gt;&lt;br /&gt;Today I decided to do something about it and wrote a script to remove all but the most recent builds.  After all why do I want an old build lying around as that's what Git of Subversion is for!&lt;br /&gt;&lt;br /&gt;If you want to give it a try you can download the script from &lt;a href="http://github.com/alexrothenberg/purge_old_cruise_builds"&gt;http://github.com/alexrothenberg/purge_old_cruise_builds&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This seems to be working for me and I'd love to hear if I'm making some assumptions you need to change to adapt it to your uses.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-2474421813173225023?l=www.alexrothenberg.com' alt='' /&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/BQX2mnSXwE4" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2010/09/29/purging-old-cruise-builds.html</feedburner:origLink></entry>
 
 <entry>
   <title>Use dashes not underscores in your domain name</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/dX-21uCxyTo/use-dashes-not-underscores-in-your.html" />
   <published>2010-09-24T00:00:00-07:00</published>
   <updated>2010-09-24T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2010/09/24/use-dashes-not-underscores-in-your</id>
   <content type="html">I recently ran into an issue where users hitting my development server with Internet Explorer kept getting redirected back to my login page no matter how many times they signed in.  Everything worked fine for all other browsers I tested and it even worked fine on Internet Explorer when pointing at http://localhost.&lt;br /&gt;&lt;br /&gt;After much investigating it turns out the problem lies in the name of my development server.  I picked a name like http://myapp_dev.alexrothenberg.com and it was the underscore in myapp_dev that caused the problem.  It turns out that IE will not set a session cookie for a domain with a hostname that contains an underscore.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/b/ieinternals/archive/2009/08/20/wininet-ie-cookie-internals-faq.aspx"&gt;According to microsoft&lt;/a&gt; this is not a bug but a feature &lt;br /&gt;&lt;blockquote&gt;Q5: IE won’t set a cookie when the hostname/domain contains an underscore?&lt;br /&gt;&lt;br /&gt;A: Correct. Technically, underscore is not a DNS character, and while Windows will let you use an underscore when naming your machine, it warns you that doing so may cause problems. One such problem is that WinINET blocks attempts to set cookies on such domains.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;OK, so it looks like IE will let me go to the page but doesn't set the session cookie so my site sees each request as part of a new session by an unauthenticated user and redirects to the login page over and over.  &lt;br /&gt;&lt;br /&gt;I did a little more research and &lt;a href="http://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names"&gt;according to Wikipedia&lt;/a&gt; Microsoft is right and underscores are not allowed in hostnames&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The Internet standards (Request for Comments) for protocols mandate that component hostname labels may contain only the ASCII letters 'a' through 'z' (in a case-insensitive manner), the digits '0' through '9', and the hyphen ('-')  ...&lt;br /&gt;While a hostname may not contain other characters, such as the underscore character (_), other DNS names may contain the underscore.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I'm not sure why IE allows the browsing but not the cookie as that turned this into a subtle bug that was especially hard to track down since Firefox, Safari and Chrome all set the cookie so my site works.  From now on I'll have to remember not to use underscores but to use dashes instead like http://myapp-dev.alexrothenberg.com which should work across all browsers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-1190859133036924356?l=www.alexrothenberg.com' alt='' /&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/dX-21uCxyTo" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2010/09/24/use-dashes-not-underscores-in-your.html</feedburner:origLink></entry>
 
 <entry>
   <title>Its not too late to solve a Y2K bug - I found one in 2010</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/B26NnqAn4No/its-not-too-late-to-solve-y2k-bug-i.html" />
   <published>2010-03-14T00:00:00-08:00</published>
   <updated>2010-03-14T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2010/03/14/its-not-too-late-to-solve-y2k-bug-i</id>
   <content type="html">&lt;p&gt;
  I thought a historical opportunity had passed me by, but a full decade after the turn of the millennium in 2010 I found my first Y2K bug! If you, like me, were working in eCommerce (who remembers that buzzword?) in the late 1990s and thought you missed your chance I'm here to tell you its still not too late. As long as you work for the right company with the enough legacy technology around you can still find a Y2K bug of your own!&lt;br&gt;
  &lt;br&gt;
  &lt;span style="font-weight:bold;"&gt;What was going on?&lt;/span&gt;&lt;br&gt;
  &lt;br&gt;
  I was writing a new Rails application on top of an old Oracle database. The database had a constraint&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;pre class="old_code"&gt;
&lt;br&gt;graduationdate BETWEEN TO_DATE('01-JAN-1900','DD-MON-YYYY') AND TO_DATE('31-DEC-2100','DD-MON-YYYY')&lt;br&gt;
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  To me this looked like a basic check to make sure the date was within a 300 year range as a basic sanity-check. I implemented an ActiveRecord validation in my model&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="n"&gt;validate&lt;/span&gt; &lt;span class="ss"&gt;:validate_graduation_date&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_graduation_date&lt;/span&gt;
  &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;graduationdate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt;
    &lt;span class="n"&gt;earliest_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;latest_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;01-JAN-1900&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;31-DEC-2100&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:graduationdate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;must be between 01-JAN-1900 and 31-DEC-2100&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;graduationdate&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;earliest_date&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;graduationdate&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;latest_date&lt;/span&gt;  
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Of course I had unit tests that all passed&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="gherkin"&gt;describe &amp;#39;graduation date&amp;#39; do
  it &amp;#39;should not allow July 4, 1776&amp;#39; do
    education = Factory.build :education, :graduationdate=&amp;gt;Date.parse(&amp;#39;04-JUL-1776&amp;#39;)
    education.should_not be_valid
  end
  it &amp;#39;should allow Aug 1 1970&amp;#39; do
    education = Factory.build :education, :graduationdate=&amp;gt;Date.parse(&amp;#39;01-AUG-1970&amp;#39;)
    education.should be_valid
  end
  it &amp;#39;should allow Mar 15 2000&amp;#39; do
    education = Factory.build :education, :graduationdate=&amp;gt;Date.parse(&amp;#39;15-MAR-2000&amp;#39;)
    education.should be_valid
  end
  it &amp;#39;should not allow Jan 1, 2525&amp;#39; do
    education = Factory.build :education, :graduationdate=&amp;gt;Date.parse(&amp;#39;01-JAN-2525&amp;#39;)
    education.should_not be_valid
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  BUT once I went into production with my legacy database I started getting errors. So I took a look at one of the rows giving me an error and discovered the graduation date was &lt;b&gt;01-JAN-00&lt;/b&gt;. AHA a 2-digit year. That doesn't look good and there were over 100,000 rows with this problem.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;pre class="old_code"&gt;
select count(*) from education where graduationdate = to_date('01-jan-1900')
COUNT(*)               
---------------------- 
116232       
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Once I realized that the database contained data for January 1st 1900 and I discovered the Oracle BETWEEN function is inclusive I was able to solve my problem by changing my ActiveRecord validation to have a &lt;code&gt;&amp;gt;= and lt;=&lt;/code&gt;.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="n"&gt;validate&lt;/span&gt; &lt;span class="ss"&gt;:validate_graduation_date&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_graduation_date&lt;/span&gt;
  &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;graduationdate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt;
    &lt;span class="n"&gt;earliest_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;latest_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;01-JAN-1900&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;31-DEC-2100&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:graduationdate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;must be between 01-JAN-1900 and 31-DEC-2100&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;graduationdate&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;earliest_date&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;graduationdate&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;latest_date&lt;/span&gt;  
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  I added some specs to test my boundary conditions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;should not allow Dec 31 1899&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;education&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="ss"&gt;:education&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:graduationdate&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;31-DEC-1899&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;education&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should_not&lt;/span&gt; &lt;span class="n"&gt;be_valid&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;should allow Jan 1 1900&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;education&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="ss"&gt;:education&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:graduationdate&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;01-JAN-1900&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;education&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;be_valid&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;should allow Dec 31 2099&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;education&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="ss"&gt;:education&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:graduationdate&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;31-DEC-2099&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;education&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;be_valid&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;should allow Jan 1 2100&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;education&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="ss"&gt;:education&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:graduationdate&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="no"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;01-JAN-2100&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;education&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should_not&lt;/span&gt; &lt;span class="n"&gt;be_valid&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;b&gt;So what's the moral?&lt;/b&gt;&lt;br&gt;
  &lt;br&gt;
  I'm not sure but when you're have to integrate with a legacy system you should account for the absurd - in my case a job application from a candidate who graduated more than 100 years ago!&lt;br&gt;
  &lt;br&gt;
  And if you feel like you missed out on a once-in-a-lifetime opportunity to work on Y2K bugs don't despair. They are still out there!
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/B26NnqAn4No" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2010/03/14/its-not-too-late-to-solve-y2k-bug-i.html</feedburner:origLink></entry>
 
 <entry>
   <title>What to do when ActiveRecord thinks an Oracle key is a decimal</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/mwux-XiIz5M/what-to-do-when-activerecord-thinks.html" />
   <published>2010-01-27T00:00:00-08:00</published>
   <updated>2010-01-27T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2010/01/27/what-to-do-when-activerecord-thinks</id>
   <content type="html">&lt;p&gt;
  I recently created a model for an existing database table using the &lt;a href="http://www.alexrothenberg.com/2009/11/generate-models-from-tables-legacy-data.html"&gt;legacy_data gem&lt;/a&gt; and was confused when my primary key showed up in scientific notation. It turned out the issue was due to sloppiness in the table definition and could be easily fixed once I understood what ActiveRecord was doing.&lt;br&gt;
  &lt;br&gt;
  I created a &lt;code&gt;Person&lt;/code&gt; model connected to the &lt;code&gt;people&lt;/code&gt; table&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  but when I went into script/console the primary key showed up as a &lt;code&gt;BigDecimal&lt;/code&gt; when I expected an &lt;code&gt;integer&lt;/code&gt;.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;pre class="old_code"&gt;
$ script/console 
Loading development environment (Rails 2.3.4)
&gt;&gt; Person.first.id
=&gt; #&lt;BigDecimal:37378fc,'0.1002484442 5E11',12(16)&gt;
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  This wasn't what I wanted and would cause problems in my app when it tried to build a url with that id like &lt;code&gt;http://localhost:3000/people/10024844425.0&lt;/code&gt;. The rails routing engine would see the .0, treat it as a format (like .xml or .json) and get confused. Let's look at why this is happening.&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns_hash&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;ActiveRecord::ConnectionAdapters::OracleEnhancedColumn:0x37391c0 @default=nil, @type=:decimal,&lt;/span&gt;
   &lt;span class="c1"&gt;#   @null=true, @name=&amp;quot;id&amp;quot;, @table_name=&amp;quot;people&amp;quot;, @scale=nil, @sql_type=&amp;quot;NUMBER&amp;quot;, @precision=nil,&lt;/span&gt;
   &lt;span class="c1"&gt;#   @primary=true, @forced_column_type=nil, @limit=nil&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns_hash&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:decimal&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns_hash&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;sql_type&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;NUMBER&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  We see that ActiveRecord is treating this column as a &lt;code&gt;:decimal&lt;/code&gt; because it's sql_type is &lt;code&gt;NUMBER&lt;/code&gt;. It turns out this is correct because an Oracle number is a decimal unless you specify it to have 0 digits after the decimal point (scale of 0). Here's the &lt;a href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/datatype.htm#i16209"&gt;documentation from Oracle&lt;/a&gt; (the last sentence is my bold)
&lt;/p&gt;

&lt;pre class="old_code"&gt;
NUMBER Datatype

The NUMBER datatype stores fixed and floating-point numbers. Numbers of virtually any magnitude can be stored and are
guaranteed portable among different systems operating Oracle, up to 38 digits of precision.

The following numbers can be stored in a NUMBER column:
  * Positive numbers in the range 1 x 10-130 to 9.99...9 x 10125 with up to 38 significant digits
  * Negative numbers from -1 x 10-130 to 9.99...99 x 10125 with up to 38 significant digits
  * Zero
  * Positive and negative infinity (generated only by importing from an Oracle Version 5 database)

For numeric columns, you can specify the column as:
  column_name NUMBER 

Optionally, you can also specify a precision (total number of digits) and scale (number of digits to the right of the decimal point):
  column_name NUMBER (precision, scale) 

If a precision is not specified, the column stores values as given. If no scale is specified, the scale is zero.

Oracle guarantees portability of numbers with a precision equal to or less than 38 digits. You can specify a scale and no precision:
  column_name NUMBER (*, scale) 

In this case, the precision is 38, and the specified scale is maintained.

&lt;b&gt;When you specify numeric fields, it is a good idea to specify the precision and scale. This provides extra integrity checking on input.&lt;/b&gt;
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Let's look in my database and sure enough the ID is a number&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
$ sqlplus myusername/mypassword@localhost:1521/mydatabase.world
SQL*Plus: Release 10.2.0.4.0 - Production on Wed Jan 27 09:15:09 2010
Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

Connected to:
Oracle Database 10g Release 10.2.0.4.0 - Production
SQL&gt; desc people;
Name        Null?    Type
----------------------------------------- -------- ----------------------------
ID                   NUMBER
NAME                 VARCHAR2(10)
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  If you are allowed to change your database you can create a migration like&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;$ script/generate migration change_person_id_to_integer&lt;br&gt;STUBBING MckinseyLDAP&lt;br&gt;      exists  db/migrate&lt;br&gt;      create  db/migrate/20100127145747_change_person_id_to_integer.rb&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  now edit the migration&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChangePersonIdToInteger&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;up&lt;/span&gt;
    &lt;span class="n"&gt;change_column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:people&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:integer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;down&lt;/span&gt;
    &lt;span class="n"&gt;change_column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:people&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:decimal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  In my case there were other applications using this table and I was not allowed to change it so I implemented a fix in Ruby to tell my model to treat this column as an integer even though it was defined as a decimal in the database.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;#config/initializers/legacy_data_type_coercion.rb&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;LegacyDataTypeCoercion&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_integer_columns&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;col_names&lt;/span&gt;
    &lt;span class="n"&gt;col_names&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;col_name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;columns_hash&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;col_name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;instance_eval&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="vi"&gt;@type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:integer&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;LegacyDataTypeCoercion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;#app/models/person.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;set_integer_columns&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  We defined a method &lt;code&gt;set_integer_columns&lt;/code&gt; that will force ActiveRecord to treat the columns we specify as integers. In our Person model we declare &lt;code&gt;:id&lt;/code&gt; is an integer column. Let's test it out!&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
$ script/console 
Loading development environment (Rails 2.3.4)
&gt;&gt; Person.first.id
=&gt; 10024844425
&gt;&gt; Person.columns_hash['id'].type
=&gt; :integer
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Just as expected id is now an integer and we can go ahead building the rest of our application.&lt;br&gt;
  &lt;br&gt;
  This is not an issue with all Oracle tables as if the column was defined as &lt;code&gt;NUMBER(10)&lt;/code&gt; (with a precision and implicit scale of 0) then ActiveRecord will interpret it as an integer automatically based on the parentheses in the data type - i.e NUMBER(10) &lt;a href="http://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb#L224-238"&gt;ActiveRecord&lt;/a&gt; or &lt;a href="http://github.com/rsim/oracle-enhanced/blob/master/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb#L192-197"&gt;Oracle Enhanced&lt;/a&gt;).
&lt;/p&gt;
&lt;div class="blogger-post-footer"&gt;
  &lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-5327631245171651344?l=www.alexrothenberg.com' alt=''&gt;
&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/mwux-XiIz5M" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2010/01/27/what-to-do-when-activerecord-thinks.html</feedburner:origLink></entry>
 
 <entry>
   <title>Freezing a gem that has native extensions</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/zJCLGuQaDaQ/freezing-gem-that-has-native-extensions.html" />
   <published>2010-01-13T00:00:00-08:00</published>
   <updated>2010-01-13T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2010/01/13/freezing-gem-that-has-native-extensions</id>
   <content type="html">&lt;p&gt;
  I like to freeze all the gems I use as we run in a shared hosting environment and need to our apps isolated from each other. Deployments are also handled by an operational team that does not intimately understand our applications so keeping our deployments to a single capistrano command &lt;span style="font-family:Courier new"&gt;cap&amp;nbsp;deploy:migrations&lt;/span&gt; has been a big win for us. Freezing most gems is pretty straightforward and has been built in since Rails 2.1. When dealing with a gem that requires native extensions to be built there's only one additional step to add to your Capfil.&lt;br&gt;
  &lt;br&gt;
  Let's say we want to localize &lt;a href="http://github.com/whymirror/hpricot"&gt;hpricot&lt;/a&gt; which does include native C extensions.&lt;br&gt;
  &lt;br&gt;
  First tell Rails about your gem by adding a config.gem line to your environment.rb&lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;Rails::Initializer.run do |config|&lt;br&gt;  ...&lt;br&gt;  config.gem 'hpricot'&lt;br&gt;  ...&lt;br&gt;end&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now we can ask rails about its configured gems&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;  $ rake gems&lt;br&gt;  (in /Users/alexrothenberg/ruby/my_project)&lt;br&gt;   - [I] hpricot &lt;br&gt;&lt;br&gt;   I = Installed&lt;br&gt;   F = Frozen&lt;br&gt;   R = Framework (loaded before rails starts)&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  The 'I' means its hpricot is installed on my system but not frozen in the application. If you see '[]' instead you need to run &lt;span style="font-family:Courier new"&gt;sudo gem install hpricot&lt;/span&gt; (add '--source http://gemcutter.org' if necessary). At this point you could write some code to use hpricot and your application will work. But if hpricot (or the version you're expecting) is not installed on your production server you'll be in trouble.&lt;br&gt;
  &lt;br&gt;
  To freeze the gem into your vendor directory run &lt;span style="font-family:Courier new"&gt;rake gems:unpack&lt;/span&gt; (optionally you can add 'GEM=hpricot' if you just want to unpack one gem).&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;  $ rake gems:unpack &lt;br&gt;  (in /Users/alexrothenberg/ruby/my_project)&lt;br&gt;  Unpacked gem: '/Users/alexrothenberg/ruby/my_project/vendor/gems/hpricot-0.8.2'&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  We can ask rails again...&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;  $ rake gems&lt;br&gt;  (in /Users/alexrothenberg/ruby/my_project)&lt;br&gt;  The following gems have native components that need to be built&lt;br&gt;    hpricot  &lt;br&gt;&lt;br&gt;  You're running:&lt;br&gt;    ruby 1.8.6.287 at /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby&lt;br&gt;    rubygems 1.3.2 at /Users/alexrothenberg/.gem/ruby/1.8, /Library/Ruby/Gems/1.8, /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8&lt;br&gt;&lt;br&gt;  Run `rake gems:build` to build the unbuilt gems.&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Oops our vendored gem is missing hasn't built the native extensions. Not to worry the message tells us what to do and we run &lt;span style="font-family:Courier new"&gt;rake gems:build&lt;/span&gt;&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;  $ rake gems:build&lt;br&gt;  (in /Users/alexrothenberg/ruby/my_project)&lt;br&gt;  Built gem: '/Users/alexrothenberg/ruby/mars-admin/vendor/gems/hpricot-0.8.2'&lt;br&gt;  alex-rothenbergs:mars-admin alexrothenberg$ rake gems&lt;br&gt;  (in /Users/alexrothenberg/ruby/my_project)&lt;br&gt;   - [F] hpricot &lt;br&gt;&lt;br&gt;  I = Installed&lt;br&gt;  F = Frozen&lt;br&gt;  R = Framework (loaded before rails starts)&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  We can ask rails again to see that the gem is now frozen and also look in our vendor folder&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;  $ rake gems&lt;br&gt;  (in /Users/alexrothenberg/ruby/my_project)&lt;br&gt;   - [F] hpricot &lt;br&gt;&lt;br&gt;  I = Installed&lt;br&gt;  F = Frozen&lt;br&gt;  R = Framework (loaded before rails starts)&lt;br&gt;  &lt;br&gt;  $ ls vendor/gems/hpricot-0.8.2/&lt;br&gt;  total 72&lt;br&gt;  -rw-r--r--   1 alexrothenberg  staff  4672 Jan 13 12:33 CHANGELOG&lt;br&gt;  -rw-r--r--   1 alexrothenberg  staff  1048 Jan 13 12:33 COPYING&lt;br&gt;  -rw-r--r--   1 alexrothenberg  staff  9216 Jan 13 12:33 README&lt;br&gt;  -rw-r--r--   1 alexrothenberg  staff  8242 Jan 13 12:33 Rakefile&lt;br&gt;  drwxr-xr-x   4 alexrothenberg  staff   136 Jan 13 12:33 ext/&lt;br&gt;  drwxr-xr-x   3 alexrothenberg  staff   102 Jan 13 12:33 extras/&lt;br&gt;  drwxr-xr-x   6 alexrothenberg  staff   204 Jan 13 12:39 lib/&lt;br&gt;  drwxr-xr-x  11 alexrothenberg  staff   374 Jan 13 12:33 test/&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Everything looks good and you can check this into git and now have a frozen version of the hpricot gem stored with your application.&lt;br&gt;
  But if we stop here, when we deploy to our production server we'd be using the native extensions we built on your laptop which may not work on the server if you have one is 32bit and the other 64bit or you have different OS libraries installed or any number of other reasons.&lt;br&gt;
  &lt;br&gt;
  To be safe, we need to rebuild the native extensions on the server when we deploy. This is not as hard as it sounds as rails gave us the rake task &lt;span style="font-family:Courier new"&gt;rake gems:build&lt;/span&gt;. We can ask capistrano to run that command on the server by adding the following to your &lt;span style="font-family:Courier new"&gt;Capfile&lt;/span&gt;.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;after "deploy:finalize_update" do&lt;br&gt;  # build the native extensions for hpricot gem&lt;br&gt;  run "cd #{release_path} &amp;amp;&amp;amp; #{rake} RAILS_ENV=#{rails_env} gems:build GEM=hpricot"&lt;br&gt;end&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now when capistrano deploys in with all the other messages you'll see something like&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;  ...&lt;br&gt;  * executing "cd /opt/apps/my_project/releases/20100108185109 &amp;amp;&amp;amp; rake RAILS_ENV=production gems:build"&lt;br&gt;     servers: ["your.server.com"]&lt;br&gt;     [your.server.com] executing command&lt;br&gt;  ** [out :: your.server.com] (in /opt/apps/my_project/releases/20100108185109)&lt;br&gt;  ** [out :: your.server.com] Built gem: '/opt/apps/my_project/releases/20100108185109/vendor/gems/hpricot-0.8.2'&lt;br&gt;     command finished&lt;br&gt;  ...   &lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  So rails give us a few simple patterns to follow to freeze our gems in the vendor folder and with a few lines in you Capfile you can use this pattern to vendor a gem with native extensions.
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/zJCLGuQaDaQ" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2010/01/13/freezing-gem-that-has-native-extensions.html</feedburner:origLink></entry>
 
 <entry>
   <title>Generate Models from Tables - Legacy Data Gem</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/Sn_dB0DdER0/generate-models-from-tables-legacy-data.html" />
   <published>2009-11-05T00:00:00-08:00</published>
   <updated>2009-11-05T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2009/11/05/generate-models-from-tables-legacy-data</id>
   <content type="html">&lt;p&gt;
  Today I'd like to announce the release of a gem I've been working on &lt;a href="http://github.com/alexrothenberg/legacy_data"&gt;Legacy Data&lt;/a&gt;&lt;br&gt;
  &lt;br&gt;
  Getting started on a Rails project with a large existing database can be daunting. How to you extract all the information that's&lt;br&gt;
  encoded in the database? Do you have to understand the entire data model before you get started? The &lt;code&gt;models_from_tables&lt;/code&gt; generator&lt;br&gt;
  in the &lt;code&gt;legacy_data&lt;/code&gt; gem can help! This generator looks into your existing database and generates ActiveRecord models based on the&lt;br&gt;
  information encoded in it.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;h2&gt;
  How to use it
&lt;/h2&gt;
&lt;p&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;To generate an ActiveRecord model for each table in the database just type&lt;br&gt;
    &lt;code&gt;script/generate models_from_tables&lt;/code&gt;&lt;br&gt;
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;If you don't want all tables in the database tell it which table to model&lt;br&gt;
    &lt;code&gt;script/generate models_from_tables --table-name comments&lt;/code&gt;&lt;br&gt;
    This uses any foreign_key constraints in the database to spider the database and model the comments table and all associated tables.&lt;br&gt;
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;If you &lt;em&gt;really&lt;/em&gt; only want the comments table tell it not to follow any foreign_keys&lt;br&gt;
    &lt;code&gt;script/generate models_from_tables --table-name comments --skip-associated&lt;/code&gt;&lt;br&gt;
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;If you use &lt;a href="http://github.com/thoughtbot/factory_girl"&gt;factory girl&lt;/a&gt; (and everyone should) it will generate a simple factory for each model it generates&lt;br&gt;
    &lt;code&gt;script/generate models_from_tables --table-name comments --with-factories&lt;/code&gt;&lt;br&gt;
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  &lt;br&gt;
  (You do need to install the plugin &lt;code&gt;gem install legacy_data&lt;/code&gt; as long as http://gemcutter.org is one of your gem sources)&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;h3&gt;
  Examples
&lt;/h3&gt;
&lt;p&gt;
  &lt;br&gt;
  Several examples come with the gem source in the &lt;a href="http://github.com/alexrothenberg/legacy_data/tree/master/examples/"&gt;examples folder on github&lt;/a&gt;. These include&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;A simple blog database tested with MySQL and Sqlite3
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;The Drupal 6.14 database tested with MySQL
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;The J2EE Petstore example tested with MySQL, Sqlite3 and Oracle
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;h2&gt;
  What kind of information can it extract from the database?
&lt;/h2&gt;
&lt;p&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;h3&gt;
  Associations
&lt;/h3&gt;
&lt;p&gt;
  &lt;br&gt;
  If the database contains foreign_key constraints it uses them to build &lt;code&gt;has_many&lt;/code&gt; or &lt;code&gt;belongs_to&lt;/code&gt; associations&lt;br&gt;
  in your ActiveRecord models&lt;br&gt;
&lt;/p&gt;
&lt;h3&gt;
  Validation constraints
&lt;/h3&gt;
&lt;p&gt;
  &lt;br&gt;
  It will generate the following types of validation constraints in your models&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;validates_uniqueness_of&lt;/strong&gt; - For columns where the database has an index that enforces uniqueness
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;validates_presence_of&lt;/strong&gt; - When the database column is non-nullable
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;validates_inclusion_of&lt;/strong&gt; - For non-nullable boolean columns and custom constraints with a SQL rule &lt;em&gt;flag IN ('Y', 'N')&lt;/em&gt;
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;validates_numericality_of&lt;/strong&gt; - For integer columns (nullable and non-nullable)
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;custom validation&lt;/strong&gt; - For custom SQL validation rules in the database it puts a placeholder in your model with the original SQL for you to translate into Ruby
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;h3&gt;
  Non-Rails naming conventions
&lt;/h3&gt;
&lt;p&gt;
  &lt;br&gt;
  Since the database is existing it's likely that it doesn't follow Rails naming conventions. Not to worry as the generator will&lt;br&gt;
  put the non-standard name into the generated models if it needs to.&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  What kinds of non-standard names can it generate?&lt;br&gt;
  &lt;br&gt;
  Let's look at a sample output&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;

  &lt;span class="n"&gt;set_table_name&lt;/span&gt;  &lt;span class="ss"&gt;:tbpost&lt;/span&gt;
  &lt;span class="n"&gt;set_primary_key&lt;/span&gt; &lt;span class="ss"&gt;:postid&lt;/span&gt;
  
  &lt;span class="c1"&gt;# Relationships&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:foreign_key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:postid&lt;/span&gt;

  &lt;span class="c1"&gt;# Constraints&lt;/span&gt;
  &lt;span class="n"&gt;validates_presence_of&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:body&lt;/span&gt;
  
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Class Names&lt;/strong&gt; - It named the model &lt;em&gt;Post&lt;/em&gt; instead of the Rails convention &lt;em&gt;Tbpost&lt;/em&gt;. The generator could not do this itself but knowing the conventions will often not apply to legacy databases it pauses after spidering the database giving you a chance to override the table to class name mapping. It generates a yaml file &lt;code&gt;app/models/table_mappings.yml&lt;/code&gt; where you can verify or change any class name before proceeding to generate the models.
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Table Names&lt;/strong&gt; - It overrode the table name since the actual name &lt;em&gt;tbpost&lt;/em&gt; does not match the Rails naming convention &lt;em&gt;posts&lt;/em&gt;
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Primary Keys&lt;/strong&gt; - It overrode the primary key since the actual column &lt;em&gt;postid&lt;/em&gt; does not match the Rails naming convention &lt;em&gt;id&lt;/em&gt;
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;Foreign Keys&lt;/strong&gt; - It overrode the foreign key on the comment table to be &lt;em&gt;postid&lt;/em&gt; instead of the Rails naming convention &lt;em&gt;id&lt;/em&gt;
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/Sn_dB0DdER0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/11/05/generate-models-from-tables-legacy-data.html</feedburner:origLink></entry>
 
 <entry>
   <title>PL/SQL debugging information now a part of Oracle Enhanced Adapter v1.2.2</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/LYHI0yRw0d8/plsql-debugging-information-now-part-of.html" />
   <published>2009-10-02T00:00:00-07:00</published>
   <updated>2009-10-02T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/10/02/plsql-debugging-information-now-part-of</id>
   <content type="html">Raimonds Simanovskis has just published a &lt;a href="http://blog.rayapps.com/2009/09/28/new-features-in-activerecord-oracle-enhanced-adapter-version-1-2-2/"&gt;version 1.2.2 of the Oracle Enhanced Adapter&lt;/a&gt; that includes the ability to capture dbms_output debug statements from your pl/sql code in the Rails log file.  This is a bit of code that I &lt;a href="http://github.com/rsim/oracle-enhanced/commit/00084e4e97d94cdab04ca1eb16275e0ed88c9490"&gt;wrote&lt;/a&gt; and &lt;a href="http://www.alexrothenberg.com/2009/08/how-to-capture-oracles-dbmsoutput-in.html"&gt;blogged about&lt;/a&gt; a few months ago so not only do I think its useful but am very excited to have contributed to something many others use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-820689130821847422?l=www.alexrothenberg.com' alt='' /&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/LYHI0yRw0d8" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/10/02/plsql-debugging-information-now-part-of.html</feedburner:origLink></entry>
 
 <entry>
   <title>Using the Whenever gem to manage scheduled cron jobs without installing it on the server</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/gr-qu4eLMVA/using-whenever-gem-to-manage-scheduled.html" />
   <published>2009-09-30T00:00:00-07:00</published>
   <updated>2009-09-30T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/09/30/using-whenever-gem-to-manage-scheduled</id>
   <content type="html">&lt;p&gt;
  I've been using &lt;a href="http://github.com/javan/whenever"&gt;Javan's Whenever gem&lt;/a&gt; to manage scheduled jobs in my project and its fantastic!! There are many existing resources where you can learn more (&lt;a href="http://github.com/javan/whenever"&gt;readme&lt;/a&gt;, &lt;a href="http://railscasts.com/episodes/164-cron-in-ruby"&gt;railscast&lt;/a&gt; &lt;a href="http://groups.google.com/group/whenever-gem"&gt;google group&lt;/a&gt;) but I'd like to describe the specific way I'm using it&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;When the gem is not installed on my server
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;How administrators can use Capistrano to both schedule and unschedule your jobs
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;How to use a library such as the Oracle client that requires certain environment variables
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  At the end of the day we want to have 2 capistrano tasks we can run to have cron call a rake task of ours on the schedule we want.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;pre class="old_code"&gt;
  cap schedule_jobs
  cap unschedule_jobs
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  If we want to get fancy and pass a custom configuration argument that will be passed into the rake task.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="old_code"&gt;
  cap schedule_jobs SOME_CONFIGURATION=false
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;h2&gt;
  When the gem is not installed on my server
&lt;/h2&gt;
&lt;p&gt;
  &lt;br&gt;
  Let's start with the Capfile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;#Capfile&lt;/span&gt;
&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Schedule the jobs&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:schedule_job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:roles&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:only&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:primary&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;some_configuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SOME_CONFIGURATION&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;#default to true&lt;/span&gt;
  &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;RAILS_ENV=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;rails_env&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s2"&gt;&amp;quot;APP_PATH=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;current_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s2"&gt;&amp;quot;SOME_CONFIGURATION=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;some_configuration&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;cd &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;current_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;rake&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; whenever:update_crontab &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Unschedule the jobs&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:unschedule_job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:roles&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:only&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:primary&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;cd &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;current_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;rake&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; whenever:update_crontab  UNSCHEDULE=true&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  How does this differ from the &lt;a href="http://github.com/javan/whenever/blob/master/README.rdoc"&gt;example&lt;/a&gt; on the whenever site? Since the gem is not installed on the server we cannot call whenever from the command line so invoke the whenever:update_crontab rake task instead and to allow administrators to easily disable the scheduled jobs we define the unschedule_jobs capistrano task. Let's take a look at the &lt;span style="font-family: 'courier new';"&gt;whenever:update_crontab&lt;/span&gt; Rake task that gets this all done.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;#lib/tasks/whenever.rake&lt;/span&gt;
&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:whenever&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;updates crontab with our scheduled jobs&amp;quot;&lt;/span&gt;  
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:update_crontab&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:load_whenever_gem&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;     
    &lt;span class="no"&gt;Whenever&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CommandLine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;:update&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:identifier&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;YOUR_APP_NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:load_whenever_gem&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;     
    &lt;span class="k"&gt;begin&lt;/span&gt;
      &lt;span class="n"&gt;gem_dir_root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/vendor/gems/&amp;quot;&lt;/span&gt;
      &lt;span class="n"&gt;chronic_gem_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/vendor/gems/*&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;detect&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;subdir&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;subdir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gem_dir_root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^(\w+-)?chronic-(\d+)/&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;subdir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/lib/chronic.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;chronic_gem_dir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/lib/chronic&amp;quot;&lt;/span&gt;

      &lt;span class="n"&gt;whenever_gem_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/vendor/gems/*&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;detect&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;subdir&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;subdir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gem_dir_root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^(\w+-)?whenever-(\d+)/&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;subdir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/lib/whenever.rb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;whenever_gem_dir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/lib/whenever&amp;quot;&lt;/span&gt;

    &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;MissingSourceFile&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Cannot find Whenever or Chronic : &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  The actual whenever:update_crontab task just does the same the command line does but unless you add &lt;span style="font-family: 'courier new';"&gt;config.gem 'whenever'&lt;/span&gt; to your environment (which I don't since whenever is not needed by my app at runtime) we also have the other task that loads whenever and chronic from the vendor/gems directory.&lt;br&gt;
  &lt;br&gt;
  At this point we've gotten Capistrano calling a rake task to invoke whenever even though the gem is localized in my application but not installed on the server.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;h2&gt;
  How administrators can use capistrano to both schedule and unschedule your jobs
&lt;/h2&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  The whenever gem does not have any support for unscheduling but it will schedule whatever is included in your schedule.rb file so if that file tells it to schedule nothing that's the same as unscheduling. Its easy to do that by wrapping the entire file with &lt;span style="font-family: 'courier new';"&gt;unless ENV['UNSCHEDULE']&lt;/span&gt; (remember the UNSCHEDULE parameter we passed in the Capfile?)&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;#config/schedule.rb&lt;/span&gt;
&lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;UNSCHEDULE&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;MyApp&lt;/span&gt;
    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Job&lt;/span&gt;
      &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CronRakeTask&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Whenever&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Job&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Default&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;output&lt;/span&gt;
          &lt;span class="n"&gt;path_required&lt;/span&gt;
          &lt;span class="s2"&gt;&amp;quot;cd &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; /usr/bin/env /usr/local/bin/cron_rake &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; SOME_CONFIGURATION=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SOME_CONFIGURATION&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; RAILS_ENV=&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@environment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;      
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;APP_PATH&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;RAILS_ROOT&lt;/span&gt; 
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;RAILS_ENV&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;production&amp;#39;&lt;/span&gt;
  &lt;span class="n"&gt;every&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:at&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;10:00pm&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;do_something&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:class&lt;/span&gt;       &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Job&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CronRakeTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                            &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                            &lt;span class="ss"&gt;:path&lt;/span&gt;        &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="vi"&gt;@path&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  What's going on with the weird CronRakeTask? This brings us to the final point&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;h2&gt;
  How to use a library such as the Oracle client that requires certain environment variables
&lt;/h2&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Cron loads its environment settings differently than an interactive shell and typically does not have all the environment variables you may have in your profile file. You could solve this by adding them to the top of your crontab file but I prefer to leave that file as simple as possible and create a wrapper script to call instead of rake. Basically the CronRakeTask does the same as Whenever's built in &lt;a href="http://github.com/javan/whenever/blob/master/lib/job_types/rake_task.rb"&gt;RakeTask&lt;/a&gt; except it calls &lt;span style="font-family: 'courier new';"&gt;/usr/local/bin/cron_rake&lt;/span&gt; instead of &lt;span style="font-family: 'courier new';"&gt;rake&lt;/span&gt;.&lt;br&gt;
  &lt;br&gt;
  The cron_rake file just sets the environment variables I need then calls rake.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;pre class="old_code"&gt;
#!/bin/bash

export PATH=/usr/local/lib/ruby-enterprise/bin:$PATH
export ORACLE_HOME=/opt/oracle
export LD_LIBRARY_PATH=/opt/oracle:$LD_LIBRARY_PATH

rake $@
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  As I said in the beginning since I've been using the Whenever gem I no longer need to manually edit my crontab files ever and I can enable my jobs as part of my normal deployment process. Its wonderful and I think everyone should use it!
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/gr-qu4eLMVA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/09/30/using-whenever-gem-to-manage-scheduled.html</feedburner:origLink></entry>
 
 <entry>
   <title>How to capture Oracle's dbms_output in your Rails log file</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/6Si_t3IYAco/how-to-capture-oracles-dbmsoutput-in.html" />
   <published>2009-08-19T00:00:00-07:00</published>
   <updated>2009-08-19T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/08/19/how-to-capture-oracles-dbmsoutput-in</id>
   <content type="html">I have been writing a rails application on top of a large existing Oracle database where each table has 5+ triggers that each call several stored procedures and each of those PL/SQL stored procedures is hundreds of lines long.  Often a simple update statement fails with an ORA-xxxx exception coming from deep in the PL/SQL code and it can be tough to figure out what's gone wrong.&lt;br /&gt;&lt;br /&gt;The usual way Oracle database folks figure out what's going on is to put print statements in their code.  In oracle this looks like&lt;br /&gt;&lt;div&gt;&lt;pre class="old_code"&gt;  dbms_output.put_line('hi i hit this line of pl/sql');&lt;/pre&gt;&lt;/div&gt;When you're using an Oracle editor like TOAD or SQLDeveloper you have to turn output on and then will see anything that's printed.&lt;br /&gt;&lt;pre class="old_code"&gt;  set serveroutput on;&lt;/pre&gt;This is great if you divide the application between Rails &lt;br /&gt;  and Database developers and assume each group can work independently to write perfect code but what about the real world!  &lt;br /&gt;  Today I want to show you how I monkey patched the &lt;a href="http://github.com/rsim/oracle-enhanced"&gt;Oracle Enhanced Adapter&lt;/a&gt; to stick the dbms_output into &lt;br /&gt;  the rails log file.&lt;br /&gt;&lt;div&gt;Let's start with an simple example of a simple PL/SQL function that tells you if a string is more than 5 characters long (with some simple debugging print statements).&lt;/div&gt;&lt;pre class="old_code"&gt;  CREATE OR REPLACE FUNCTION&lt;br /&gt;  MORE_THAN_FIVE_CHARACTERS_LONG (some_text VARCHAR2) RETURN INTEGER&lt;br /&gt;  AS&lt;br /&gt;  longer_than_five INTEGER;&lt;br /&gt;  BEGIN&lt;br /&gt;    dbms_output.put_line('before the if -' || some_text || '-');&lt;br /&gt;    IF length(some_text) &gt; 5 THEN&lt;br /&gt;      dbms_output.put_line('it is longer than 5');&lt;br /&gt;      longer_than_five := 1;&lt;br /&gt;    ELSE&lt;br /&gt;      dbms_output.put_line('it is 5 or shorter');&lt;br /&gt;      longer_than_five := 0;&lt;br /&gt;    END IF;&lt;br /&gt;    dbms_output.put_line('about to return: ' || longer_than_five);&lt;br /&gt;    RETURN longer_than_five;&lt;br /&gt;  END;&lt;/pre&gt;Now we can run the following in TOAD&lt;br /&gt;&lt;pre class="old_code"&gt;  set serveroutput on;&lt;br /&gt;  select MORE_THAN_FIVE_CHARACTERS_LONG('a long string') from dual;&lt;br /&gt;  select MORE_THAN_FIVE_CHARACTERS_LONG('short') from dual;&lt;/pre&gt;And we get this output&lt;br /&gt;&lt;pre class="old_code"&gt;  MORE_THAN_FIVE_CHARACTERS_LONG('ALONGSTRING') &lt;br /&gt;  --------------------------------------------- &lt;br /&gt;  1                                             &lt;br /&gt;&lt;br /&gt;  1 rows selected&lt;br /&gt;&lt;br /&gt;  before the if -a long string-&lt;br /&gt;  it is longer than 5&lt;br /&gt;  about to return: 1&lt;br /&gt;&lt;br /&gt;  MORE_THAN_FIVE_CHARACTERS_LONG('SHORT') &lt;br /&gt;  --------------------------------------- &lt;br /&gt;  0                                       &lt;br /&gt;&lt;br /&gt;  1 rows selected&lt;br /&gt;&lt;br /&gt;  before the if -short-&lt;br /&gt;  it is 5 or shorter&lt;br /&gt;  about to return: 0&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;To get the same in our Rails app we just need to monkey patch the OracleEnhancedAdapter by copying what's below into your project as &lt;span style="font-family:'courier new';"&gt;config/initializers/oracle_enhanced_adapter.rb&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="old_code"&gt;  module ActiveRecord&lt;br /&gt;    module ConnectionAdapters&lt;br /&gt;      class OracleEnhancedAdapter &lt; AbstractAdapter&lt;br /&gt;        DBMS_OUTPUT_BUFFER_SIZE = 10000  #can be 1-1000000&lt;br /&gt;        DBMS_LINE_MAX_SIZE      = 1000  &lt;br /&gt;        def enable_dbms_output&lt;br /&gt;          @enable_dbms_output = true&lt;br /&gt;          execute "BEGIN dbms_output.enable(#{DBMS_OUTPUT_BUFFER_SIZE}); END;"&lt;br /&gt;        end&lt;br /&gt;        def disable_dbms_output&lt;br /&gt;          @enable_dbms_output = false&lt;br /&gt;          execute "BEGIN dbms_output.disable(); END;"&lt;br /&gt;        end&lt;br /&gt;        def dbms_output_enabled?&lt;br /&gt;          @enable_dbms_output&lt;br /&gt;        end&lt;br /&gt;&lt;br /&gt;        protected&lt;br /&gt;          def log(sql, name)&lt;br /&gt;            super(sql, name)&lt;br /&gt;          ensure&lt;br /&gt;            log_all_dbms_output if dbms_output_enabled?&lt;br /&gt;          end&lt;br /&gt;&lt;br /&gt;        private  &lt;br /&gt;          def log_next_line_of_dbms_output&lt;br /&gt;            dbms_output_text, status = @connection.exec "BEGIN dbms_output.get_line(:return, :status); END;", ' '*DBMS_LINE_MAX_SIZE, 1&lt;br /&gt;            got_text = (status == 0)&lt;br /&gt;            @logger.debug "DBMS_OUTPUT: #{dbms_output_text}" if got_text&lt;br /&gt;            got_text&lt;br /&gt;          end&lt;br /&gt;        &lt;br /&gt;          def log_all_dbms_output&lt;br /&gt;            while log_next_line_of_dbms_output do&lt;br /&gt;            end&lt;br /&gt;          end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To use it let's show a quick script/console session&lt;br /&gt;&lt;pre class="old_code"&gt;  &gt;&gt; ActiveRecord::Base.connection.enable_dbms_output&lt;br /&gt;  =&gt; []&lt;br /&gt;  &gt;&gt; ActiveRecord::Base.connection.select_all("select MORE_THAN_FIVE_CHARACTERS_LONG('a long string') from dual")&lt;br /&gt;  =&gt; [{"more_than_five_characters_long('alongstring')"=&gt;1}]&lt;br /&gt;&lt;/pre&gt;And what's in log/development.log&lt;br /&gt;&lt;pre class="old_code"&gt;&lt;br /&gt;    SQL (27.0ms)   BEGIN dbms_output.enable(10000); END;&lt;br /&gt;    SQL (25.9ms)   select MORE_THAN_FIVE_CHARACTERS_LONG('a long string') from dual&lt;br /&gt;  DBMS_OUTPUT: before the if -a long string-&lt;br /&gt;  DBMS_OUTPUT: it is longer than 5&lt;br /&gt;  DBMS_OUTPUT: about to return: 1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is admittedly a very simple example but I have used this in a real application where I am updating several related ActiveRecord objects and seeing the DBMS_OUTPUT inline with the various SQL update statements has been extremely useful in tracking down a real bug in the PL/SQL procedure that has been in our system for over a year!&lt;br /&gt;&lt;br /&gt;I've &lt;a href="http://groups.google.com/group/oracle-enhanced/browse_thread/thread/91574e45b1e2cf09"&gt;submitted&lt;/a&gt; this as a &lt;a href="http://github.com/alexrothenberg/oracle-enhanced/commit/00084e4e97d94cdab04ca1eb16275e0ed88c9490"&gt;patch&lt;/a&gt; to the Oracle Enhanced Adapter so perhaps it will be included at some point so you wont have to do the monkey patching yourself.  I was somewhat surprised not to find anything similar out there so if you know of something please leave a comment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-7197348622671778074?l=www.alexrothenberg.com' alt='' /&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/6Si_t3IYAco" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/08/19/how-to-capture-oracles-dbmsoutput-in.html</feedburner:origLink></entry>
 
 <entry>
   <title>One year of blogging</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/QdWKAm_wrP0/one-year-of-blogging.html" />
   <published>2009-07-22T00:00:00-07:00</published>
   <updated>2009-07-22T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/07/22/one-year-of-blogging</id>
   <content type="html">I just noticed that its been a year since my first post and thought I'd take a moment to reflect on the experience....&lt;br /&gt;&lt;br /&gt;I set out with a goal of writing 2-3 posts a month and have managed to write 28 articles over 12 months so I feel pretty good about that.  Most of the time I've gotten excited about something I accomplished or learned during the week. The process of writing it up turned out to be as much of a learning experience for myself as the original discovery.  As they say "Teaching is the best way to learn"!&lt;br /&gt;&lt;br /&gt;I've been most surprised how easy it is to get to the top of a Google Search results list (for very specific searches of course).  With my Google Analytics tracking I can see more than 1/2 of my hits coming from search engines and not all of them are me searching for my own name :)   Its been great when I've gotten comments from people I don't know (especially when the comments are positive).&lt;br /&gt;&lt;br /&gt;Writing this blog has also helped turn my focus outward so I'm not only working on internal projects at my company but feel (in a small way) a part of the broader community.  &lt;br /&gt;&lt;br /&gt;I hope to continue in the coming year as I'm having a lot of fun so far ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-672276106815230669?l=www.alexrothenberg.com' alt='' /&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/QdWKAm_wrP0" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/07/22/one-year-of-blogging.html</feedburner:origLink></entry>
 
 <entry>
   <title>Using Github Through Draconian Proxies (Windows And Unix)</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/u8i9xOfXoLA/using-github-through-draconian-proxies.html" />
   <published>2009-06-25T00:00:00-07:00</published>
   <updated>2009-06-25T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/06/25/using-github-through-draconian-proxies</id>
   <content type="html">I came across this great set of instructions on how to tunnel through a proxy to use github&lt;span style="text-decoration: underline;"&gt; - &lt;/span&gt;&lt;a href="http://returnbooleantrue.blogspot.com/2009/06/using-github-through-draconian-proxies.html"&gt;http://returnbooleantrue.blogspot.com/2009/06/using-github-through-draconian-proxies.html&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;The proxy where I work is not &lt;span style="font-style: italic;"&gt;quite&lt;/span&gt; so draconian that I need to follow these steps but its nice to have these instructions just in case :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-1251412314005594539?l=www.alexrothenberg.com' alt='' /&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/u8i9xOfXoLA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/06/25/using-github-through-draconian-proxies.html</feedburner:origLink></entry>
 
 <entry>
   <title>Metric_fu 1.1.0 released with a patch from me</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/u_N0a1vPSaY/released-with-patch-from.html" />
   <published>2009-06-24T00:00:00-07:00</published>
   <updated>2009-06-24T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/06/24/released-with-patch-from</id>
   <content type="html">&lt;a href="http://metric-fu.rubyforge.org/"&gt;Metric_fu&lt;/a&gt; just released version 1.1.0 of their gem which I'm pleased to say includes a &lt;a href="http://github.com/jscruggs/metric_fu/commit/573afaf19e7a578aa0b161569290169d9298cf96"&gt;patch submitted by me&lt;/a&gt;.  This is exciting as its the first time I've had my code included by someone I don't know in one of the open source projects I admire.&lt;br /&gt;&lt;br /&gt;I was not originally going to make the patch as I thought I'd just hack around to fix the problem locally just enough to get it working but my friend &lt;a href="http://www.theagiledeveloper.com/"&gt;Matt&lt;/a&gt; encouraged me to fix the root cause which turned out to be not too hard and got me into the metric_fu source.  I always learn something when I read source from others I admire.&lt;br /&gt;&lt;br /&gt;The process of submitting the patch was pretty easy and I plan to make it a habit when I run into issues with other gems.  I,&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Experienced a problem and decided not to live with it&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Created a &lt;a href="http://github.com/alexrothenberg/metric_fu"&gt;fork of metric_fu&lt;/a&gt; on github&lt;/li&gt;&lt;li&gt;Cloned locally and iteratively made my changes until I had my fix complete&lt;/li&gt;&lt;li&gt;Rebased my changes into a single commit (I wrote &lt;a href="http://www.alexrothenberg.com/2009/06/changing-history-with-git-rebase-how-to.html"&gt;an article&lt;/a&gt; on this a few weeks ago)&lt;/li&gt;&lt;li&gt;Pushed my patch back to github on &lt;a href="http://github.com/alexrothenberg/metric_fu/tree/runtime_dependencies"&gt;a branch&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Submitted my patch back to Jake's repository as &lt;a href="http://github.com/jscruggs/metric_fu/issues#issue/1"&gt;an issue&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Solving the problem of gem dependencies with github names&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I am using &lt;a href="http://github.com/relevance/rcov"&gt;relevance-rcov&lt;/a&gt; instead of the rubyforge version of rcov as it has been maintained more recently and specifically fixed a segmentation fault problem I previously faced.  The problem is that I couldn't install metric_fu as it put a gem dependency on 'rcov' in its gemspec.  What seems broken is that there's no way to put a dependency on 'rcov' but have rubygems realize that 'relevance-rcov' is a fork of rcov so should satisfy the dependency.&lt;br /&gt;&lt;br /&gt;I've seen a lot of talk recently about rubygems (including &lt;a href="http://www.rubyinside.com/why-using-require-rubygems-is-wrong-1478.html"&gt;Why Using require ‘rubygems’ Is Wrong&lt;/a&gt;, &lt;a href="http://yehudakatz.com/2009/06/15/rubygems-problems-and-proposed-solutions"&gt;RubyGems: Problems and (proposed) Solutions&lt;/a&gt; and &lt;a href="http://www.rubyinside.com/rip-ruby-packaging-system-1837.html"&gt;Rip: A Next Generation Ruby Packaging System - Watch Out RubyGems!&lt;/a&gt;) but so far I haven't found a solution to the forking and naming problem emerge.&lt;br /&gt;&lt;br /&gt;For Metric_fu I decided to change the install-time dependency to a runtime one.  This solves my basic problem of not finding relevance-rcov but also allows for more flexibile use of metric_fu.  If someone does not want to generate reek or rcov metrics why should they be forced to install those gems in order to use metric_fu?  By defering the dependency until runtime we will never hit the dependency for those metrics we are not using.&lt;br /&gt;&lt;br /&gt;You can look through the &lt;a href="http://github.com/jscruggs/metric_fu/commit/573afaf19e7a578aa0b161569290169d9298cf96"&gt;commit&lt;/a&gt; to see exactly how I did this.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Deleted the install time dependencies from metric_fu.gemspec&lt;/li&gt;&lt;li&gt;Added the runtime dependencies when a specific type of metric is instantiated by&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Inserting a verify_dependencies! strategy step to the initialization in lib/base/generator.rb&lt;/li&gt;&lt;li&gt;Implementing verify_dependencies! in each of the subclasses for different metrics in lib/generators/*&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Did it with TDD writing tests around everything before implementing my changes&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Should gems use install time dependencies? Should a gem author decide which fork of a gem is required? What do you think?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-2778046913982289013?l=www.alexrothenberg.com' alt='' /&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/u_N0a1vPSaY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/06/24/released-with-patch-from.html</feedburner:origLink></entry>
 
 <entry>
   <title>Changing history with git rebase: How to combine several commits into one</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/45IHFDSA-7A/changing-history-with-git-rebase-how-to.html" />
   <published>2009-06-10T00:00:00-07:00</published>
   <updated>2009-06-10T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/06/10/changing-history-with-git-rebase-how-to</id>
   <content type="html">When I look at commits on github I'm always impressed at how concise they are.  When I read a commit I can understand the intent of the change without getting distracted by the author's journey to get there.  In contrast when I look at my commits they tend to be smaller and more incremental and meandering as I work my way down some false starts until I get to the solution I want.  I'm guessing that I'm not alone in the way I work and recently discovered &lt;a href="http://www.kernel.org/pub/software/scm/git-core/docs/git-rebase.html"&gt;git rebase&lt;/a&gt; and an &lt;a href="http://blog.madism.org/index.php/2007/09/09/138-git-awsome-ness-git-rebase-interactive"&gt;helpful tutorial&lt;/a&gt; showing how I can continue to work in my meandering style but package my changes to hide the journey before publishing to the world on github.&lt;br /&gt;&lt;br /&gt;Let me show you what I mean with some changes I recently made to &lt;a href="http://github.com/jscruggs/metric_fu/tree/master"&gt;metric_fu&lt;/a&gt;.  Over the course of a few days I made 6 small commits as you can see below.&lt;br /&gt;&lt;br /&gt;&lt;pre class="old_code"&gt;&lt;br /&gt;&gt; git log&lt;br /&gt;&lt;br /&gt;commit d4b18b16e982ac57741f7a0a12cb085bb9b0e840&lt;br /&gt;Author: Alex Rothenberg &lt;alex@alexrothenberg.com&gt;&lt;br /&gt;Date:   Mon Jun 1 09:55:37 2009 -0400&lt;br /&gt;&lt;br /&gt;    reverted rakefile&lt;br /&gt;&lt;br /&gt;commit ebda1cb67a2f0f0a85e51469d70919fa7c27d318&lt;br /&gt;Author: Alex Rothenberg &lt;alex@alexrothenberg.com&gt;&lt;br /&gt;Date:   Mon Jun 1 09:49:05 2009 -0400&lt;br /&gt;&lt;br /&gt;    refactoring of verify_dependencies&lt;br /&gt;&lt;br /&gt;commit 3d45903b64a772fd09ec07bf69880bdb29ae4944&lt;br /&gt;Author: Alex Rothenberg &lt;alex@alexrothenberg.com&gt;&lt;br /&gt;Date:   Fri May 29 20:40:49 2009 -0400&lt;br /&gt;&lt;br /&gt;    runtime dependency check for all gems&lt;br /&gt;&lt;br /&gt;commit 36e269bf8f0edccfb39cc767182406cdaa16a559&lt;br /&gt;Author: Alex Rothenberg &lt;alex@alexrothenberg.com&gt;&lt;br /&gt;Date:   Fri May 29 20:24:16 2009 -0400&lt;br /&gt;&lt;br /&gt;    logic for checking dependencies in generator base&lt;br /&gt;&lt;br /&gt;commit bb2ee9a983c6adf54a8c95ee5851c6f8d3bffaba&lt;br /&gt;Author: Alex Rothenberg &lt;alex@alexrothenberg.com&gt;&lt;br /&gt;Date:   Fri May 29 19:38:21 2009 -0400&lt;br /&gt;&lt;br /&gt;    made rcov dependency figure itself out when generating rcov metrics&lt;br /&gt;&lt;br /&gt;commit 750b000e5563e917f21eb1b7837e8001fb53f688&lt;br /&gt;Author: Alex Rothenberg &lt;alex@alexrothenberg.com&gt;&lt;br /&gt;Date:   Fri May 29 16:42:12 2009 -0400&lt;br /&gt;&lt;br /&gt;    removed gem dependency on rcov - to allow use of relevance-rcov or other github forks&lt;br /&gt;&lt;br /&gt;commit d6af5089adce9eeed4916a155c3bdaeb4be6771a&lt;br /&gt;Author: Randy Souza &lt;randy@farnsworth.(none)&gt;&lt;br /&gt;Date:   Sat May 16 08:47:37 2009 +0800&lt;br /&gt;&lt;br /&gt;    Added a simple fix for cases where Saikuro results with nested information&lt;br /&gt;    cause metrics:all to crash&lt;br /&gt;    &lt;br /&gt;    Signed-off-by: Jake Scruggs &lt;jake.scruggs@gmail.com&gt;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I am going to combine all of these into a single commit using the incredible power of git rebase.  I find the last commit I do not want to change (the one made by Randy Souza on May 16th) and issue a git rebase command with that id.&lt;br /&gt;&lt;br /&gt;&lt;pre class="old_code"&gt;&lt;br /&gt;&gt; git rebase --interactive d6af5089adce9eeed4916a155c3bdaeb4be6771a&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now my editor comes up showing the 6 changes since then giving me options of what to do.  Its very powerful, I can reorder commits, combine commits, eliminate commits.  I'm going back in time to change the past!&lt;br /&gt;&lt;br /&gt;&lt;pre class="old_code"&gt;&lt;br /&gt;pick 750b000 removed gem dependency on rcov - to allow use of relevance-rcov or other github forks&lt;br /&gt;pick bb2ee9a made rcov dependency figure itself out when generating rcov metrics&lt;br /&gt;pick 36e269b logic for checking dependencies in generator base&lt;br /&gt;pick 3d45903 runtime dependency check for all gems&lt;br /&gt;pick ebda1cb refactoring of verify_dependencies&lt;br /&gt;pick d4b18b1 reverted rakefile&lt;br /&gt;&lt;br /&gt;# Rebase d6af508..d4b18b1 onto d6af508&lt;br /&gt;#&lt;br /&gt;# Commands:&lt;br /&gt;#  p, pick = use commit&lt;br /&gt;#  e, edit = use commit, but stop for amending&lt;br /&gt;#  s, squash = use commit, but meld into previous commit&lt;br /&gt;#&lt;br /&gt;# If you remove a line here THAT COMMIT WILL BE LOST.&lt;br /&gt;# However, if you remove everything, the rebase will be aborted.&lt;br /&gt;#&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In my case I want to combine these into a single commit so I change all but the first pick command to a squash and save.&lt;br /&gt;&lt;br /&gt;&lt;pre class="old_code"&gt;&lt;br /&gt;pick 750b000 removed gem dependency on rcov - to allow use of relevance-rcov or other github forks&lt;br /&gt;squash bb2ee9a made rcov dependency figure itself out when generating rcov metrics&lt;br /&gt;squash 36e269b logic for checking dependencies in generator base&lt;br /&gt;squash 3d45903 runtime dependency check for all gems&lt;br /&gt;squash ebda1cb refactoring of verify_dependencies&lt;br /&gt;squash d4b18b1 reverted rakefile&lt;br /&gt;&lt;br /&gt;# Rebase d6af508..d4b18b1 onto d6af508&lt;br /&gt;#&lt;br /&gt;# Commands:&lt;br /&gt;#  p, pick = use commit&lt;br /&gt;#  e, edit = use commit, but stop for amending&lt;br /&gt;#  s, squash = use commit, but meld into previous commit&lt;br /&gt;#&lt;br /&gt;# If you remove a line here THAT COMMIT WILL BE LOST.&lt;br /&gt;# However, if you remove everything, the rebase will be aborted.&lt;br /&gt;#&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It now gives me a chance to edit the new commit message which it defaults to the original messages concatenated together.  This really is a single commit so if one of the original commits changed a file and a subsequent one undid the change that file will no longer appear in the list of modified files.&lt;br /&gt;&lt;br /&gt;&lt;pre class="old_code"&gt;&lt;br /&gt;&lt;br /&gt;# This is a combination of 6 commits.&lt;br /&gt;# The first commit's message is:&lt;br /&gt;removed gem dependency on rcov - to allow use of relevance-rcov or other github forks&lt;br /&gt;&lt;br /&gt;# This is the 2nd commit message:&lt;br /&gt;&lt;br /&gt;made rcov dependency figure itself out when generating rcov metrics&lt;br /&gt;&lt;br /&gt;# This is the 3rd commit message:&lt;br /&gt;&lt;br /&gt;logic for checking dependencies in generator base&lt;br /&gt;&lt;br /&gt;# This is the 4th commit message:&lt;br /&gt;&lt;br /&gt;runtime dependency check for all gems&lt;br /&gt;&lt;br /&gt;# This is the 5th commit message:&lt;br /&gt;&lt;br /&gt;refactoring of verify_dependencies&lt;br /&gt;&lt;br /&gt;# This is the 6th commit message:&lt;br /&gt;&lt;br /&gt;reverted rakefile&lt;br /&gt;&lt;br /&gt;# Please enter the commit message for your changes. Lines starting&lt;br /&gt;# with '#' will be ignored, and an empty message aborts the commit.&lt;br /&gt;# Explicit paths specified without -i nor -o; assuming --only paths...&lt;br /&gt;# Not currently on any branch.&lt;br /&gt;# Changes to be committed:&lt;br /&gt;#   (use "git reset HEAD &lt;file&gt;..." to unstage)&lt;br /&gt;#&lt;br /&gt;#       modified:   Rakefile&lt;br /&gt;#       modified:   lib/base/generator.rb&lt;br /&gt;#       modified:   lib/generators/flay.rb&lt;br /&gt;#       modified:   lib/generators/flog.rb&lt;br /&gt;#       modified:   lib/generators/rcov.rb&lt;br /&gt;#       modified:   lib/generators/reek.rb&lt;br /&gt;#       modified:   lib/generators/roodi.rb&lt;br /&gt;#       modified:   lib/generators/saikuro.rb&lt;br /&gt;#       modified:   metric_fu.gemspec&lt;br /&gt;#       modified:   spec/base/generator_spec.rb&lt;br /&gt;#       modified:   spec/generators/flay_spec.rb&lt;br /&gt;#       modified:   spec/generators/flog_spec.rb&lt;br /&gt;#       modified:   spec/generators/reek_spec.rb&lt;br /&gt;#&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Let's edit this commit message to read something like&lt;br /&gt;&lt;br /&gt;&lt;pre class="old_code"&gt;&lt;br /&gt;Changed gem dependencies from install-time in gemspec to runtime when each&lt;br /&gt;of the generators is loaded.  This allows use of github gems (i.e.&lt;br /&gt;relevance-rcov instead of rcov) and also allows you to install only the&lt;br /&gt;gems for the metrics you plan on using.&lt;br /&gt;&lt;br /&gt;                                     &lt;br /&gt;# Please enter the commit message for your changes. Lines starting&lt;br /&gt;# with '#' will be ignored, and an empty message aborts the commit.&lt;br /&gt;# Explicit paths specified without -i nor -o; assuming --only paths...&lt;br /&gt;# Not currently on any branch.&lt;br /&gt;# Changes to be committed:&lt;br /&gt;#   (use "git reset HEAD &lt;file&gt;..." to unstage)&lt;br /&gt;#&lt;br /&gt;#       modified:   Rakefile&lt;br /&gt;#       modified:   lib/base/generator.rb&lt;br /&gt;#       modified:   lib/generators/flay.rb&lt;br /&gt;#       modified:   lib/generators/flog.rb&lt;br /&gt;#       modified:   lib/generators/rcov.rb&lt;br /&gt;#       modified:   lib/generators/reek.rb&lt;br /&gt;#       modified:   lib/generators/roodi.rb&lt;br /&gt;#       modified:   lib/generators/saikuro.rb&lt;br /&gt;#       modified:   metric_fu.gemspec&lt;br /&gt;#       modified:   spec/base/generator_spec.rb&lt;br /&gt;#       modified:   spec/generators/flay_spec.rb&lt;br /&gt;#       modified:   spec/generators/flog_spec.rb&lt;br /&gt;#       modified:   spec/generators/reek_spec.rb&lt;br /&gt;#&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And that's it!  Now when we check our history we see.&lt;br /&gt;&lt;br /&gt;&lt;pre class="old_code"&gt;&lt;br /&gt;&gt; git log&lt;br /&gt;&lt;br /&gt;commit 6f389364eb972871867d3a71677b8eb7046541a2&lt;br /&gt;Author: Alex Rothenberg &lt;alex@alexrothenberg.com&gt;&lt;br /&gt;Date:   Fri May 29 16:42:12 2009 -0400&lt;br /&gt;&lt;br /&gt;    Changed gem dependencies from install-time in gemspec to runtime when each&lt;br /&gt;    of the generators is loaded.  This allows use of github gems (i.e.&lt;br /&gt;    relevance-rcov instead of rcov) and also allows you to install only the&lt;br /&gt;    gems for the metrics you plan on using.&lt;br /&gt;&lt;br /&gt;commit d6af5089adce9eeed4916a155c3bdaeb4be6771a&lt;br /&gt;Author: Randy Souza &lt;randy@farnsworth.(none)&gt;&lt;br /&gt;Date:   Sat May 16 08:47:37 2009 +0800&lt;br /&gt;&lt;br /&gt;    Added a simple fix for cases where Saikuro results with nested information&lt;br /&gt;    cause metrics:all to crash&lt;br /&gt;    &lt;br /&gt;    Signed-off-by: Jake Scruggs &lt;jake.scruggs@gmail.com&gt;&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And &lt;a href="http://github.com/alexrothenberg/metric_fu/commit/573afaf19e7a578aa0b161569290169d9298cf96"&gt;this commit&lt;/a&gt; is how I pushed this patch to github for all the world to see.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-6346906639645335189?l=www.alexrothenberg.com' alt='' /&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/45IHFDSA-7A" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/06/10/changing-history-with-git-rebase-how-to.html</feedburner:origLink></entry>
 
 <entry>
   <title>How to use dates in Rails when your database stores a string</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/OU4ACMz7l80/how-to-use-dates-in-rails-when-your.html" />
   <published>2009-05-21T00:00:00-07:00</published>
   <updated>2009-05-21T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/05/21/how-to-use-dates-in-rails-when-your</id>
   <content type="html">&lt;p&gt;
  When working with Rails there's a lot of magic that happens behind the scenes to make it easy to do complex things. Most of the time you don't need to know how that "magic" works but there are times when things don't work as expected and its helpful to dig in and understand what Rails is doing under the covers so you can change how it works. Did I just say "change how Rails works"?!? I did! Rails is opinionated software that seeks to lead you down the golden path but there are legitimate times when you have to veer off that path and Rails lets you do so. I find this most often happens to me when I'm dealing with an existing legacy database which is not setup as Rails would like.&lt;br&gt;
  &lt;br&gt;
  Today I'm going to go through an example that happened to me recently when I had an existing database that stored some dates in a text column but I needed to treat them as dates in my UI. I couldn't change the type of that column as there was another legacy application that expected it to be text.&lt;br&gt;
  &lt;br&gt;
  &lt;span style="font-size:130%;font-weight: bold;"&gt;Using Dates the Rails Way&lt;/span&gt;&lt;br&gt;
  &lt;br&gt;
  First let's look at how easy it is to work with dates when you can follow the Rails Way. Let's create a new project and add a scaffolded Person object with a date attribute called birthday.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="old_code"&gt;
rails date_select_example
cd date_select_example
script/generate scaffold person name:string birthday:date
rake db:migrate
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now if we hit the site and try to create a new person we see a screen like this&lt;br&gt;
  &lt;br&gt;
  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_36rptmL_RFc/ShbLyDIggQI/AAAAAAAADRI/M5mxXuL8rfw/s1600-h/new_person.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 241px; height: 223px;" src="http://1.bp.blogspot.com/_36rptmL_RFc/ShbLyDIggQI/AAAAAAAADRI/M5mxXuL8rfw/s320/new_person.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5338678468989190402" name="BLOGGER_PHOTO_ID_5338678468989190402"&gt;&lt;/a&gt;&lt;br&gt;
  &lt;br&gt;
  And when you click "Create"&lt;br&gt;
  &lt;br&gt;
  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_36rptmL_RFc/ShbeAUi2a1I/AAAAAAAADRk/GYT6EpIyQts/s1600-h/person_created_successfully.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 234px; height: 139px;" src="http://4.bp.blogspot.com/_36rptmL_RFc/ShbeAUi2a1I/AAAAAAAADRk/GYT6EpIyQts/s320/person_created_successfully.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5338698505390549842" name="BLOGGER_PHOTO_ID_5338698505390549842"&gt;&lt;/a&gt;&lt;br&gt;
  &lt;br&gt;
  Exactly what you want with almost no code in the view and none in the model. I did make a minor edit to the view so we would get 1960 in the year select by adding &lt;span style="font-family: courier new;"&gt;:start_year=&amp;gt;1900&lt;/span&gt; (a full documentation of &lt;a href="http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#M001666"&gt;date_select options&lt;/a&gt; are available here)&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;#app/views/people/new.html.erb&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="no"&gt;New&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% form_for(@person) &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;%= f.error_messages %&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= f.label :name %&amp;gt;&amp;lt;br /&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;    &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= f.label :birthday %&amp;gt;&amp;lt;br /&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;    &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date_select&lt;/span&gt; &lt;span class="ss"&gt;:birthday&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:start_year&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;1900&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= f.submit &amp;#39;Create&amp;#39; %&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;&amp;lt;% end %&amp;gt;&lt;/span&gt;

&lt;span class="sx"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Back&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;people_path&lt;/span&gt; &lt;span class="o"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;#app/models/person.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;span style="font-size:130%;font-weight: bold;"&gt;Errors when storing as text in the database&lt;/span&gt;&lt;br&gt;
  &lt;br&gt;
  Now what happens when you run into a case where the date is stored as a string in the database. Let's say we have an "anniversary" attribute stored as a string that we want to treat the same way as we did birthday. We create the migration.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="old_code"&gt;
script/generate migration AddAnniversaryToPerson anniversary:string
rake db:migrate
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Then add the anniversary to our view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;#app/views/people/edit.html.erb&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="no"&gt;Editing&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;% form_for(@person) &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;%= f.error_messages %&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= f.label :name %&amp;gt;&amp;lt;br /&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;    &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= f.label :birthday %&amp;gt;&amp;lt;br /&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;    &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date_select&lt;/span&gt; &lt;span class="ss"&gt;:birthday&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:start_year&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;1900&lt;/span&gt;  &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= f.label :anniversary %&amp;gt;&amp;lt;br /&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;    &amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date_select&lt;/span&gt; &lt;span class="ss"&gt;:anniversary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:start_year&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;1900&lt;/span&gt;  &lt;span class="sx"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= f.submit &amp;#39;Update&amp;#39; %&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;  &amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="sx"&gt;&amp;lt;% end %&amp;gt;&lt;/span&gt;

&lt;span class="sx"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Show&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@person&lt;/span&gt; &lt;span class="sx"&gt;%&amp;gt; |&lt;/span&gt;
&lt;span class="sx"&gt;&amp;lt;%= link_to &amp;#39;Back&amp;#39;, people_path %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_36rptmL_RFc/Shbhd6Rdh6I/AAAAAAAADRs/KU4XDoM_ICY/s1600-h/edit_person.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 236px; height: 277px;" src="http://1.bp.blogspot.com/_36rptmL_RFc/Shbhd6Rdh6I/AAAAAAAADRs/KU4XDoM_ICY/s320/edit_person.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5338702312269252514" name="BLOGGER_PHOTO_ID_5338702312269252514"&gt;&lt;/a&gt;&lt;br&gt;
  &lt;br&gt;
  It looks like we're done so we click "Update" and .. Oops. It doesn't work! We get the error &lt;span style="font-family: courier new;"&gt;1 error(s) on assignment of multiparameter attributes&lt;/span&gt;. Now we need to figure out what multiparameter attributes are and whey they're not working for us.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;pre class="old_code"&gt;
ActiveRecord::MultiparameterAssignmentErrors in PeopleController#update

1 error(s) on assignment of multiparameter attributes
RAILS_ROOT: /Users/alexrothenberg/date_select_example

Application Trace | Framework Trace | Full Trace
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/&lt;a href="http://github.com/rails/rails/blob/dc88847e5ce392eed210b97525c14fca55852867/activerecord/lib/active_record/base.rb#L3034-3063"&gt;active_record/base.rb:3061&lt;/a&gt;:in `execute_callstack_for_multiparameter_attributes'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/&lt;a href="http://github.com/rails/rails/blob/dc88847e5ce392eed210b97525c14fca55852867/activerecord/lib/active_record/base.rb#L3014-3024"&gt;active_record/base.rb:3022&lt;/a&gt;:in `assign_multiparameter_attributes'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/&lt;a href="http://github.com/rails/rails/blob/dc88847e5ce392eed210b97525c14fca55852867/activerecord/lib/active_record/base.rb#L2733-2750"&gt;active_record/base.rb:2749&lt;/a&gt;:in `attributes='
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/&lt;a href="http://github.com/rails/rails/blob/dc88847e5ce392eed210b97525c14fca55852867/activerecord/lib/active_record/base.rb#L2626-2629"&gt;active_record/base.rb&lt;/a&gt;:2627:in `update_attributes'
/Users/alexrothenberg/date_select_example/app/controllers/&lt;a href="http://github.com/alexrothenberg/date_select_example/blob/master/app/controllers/people_controller.rb#L59-72"&gt;people_controller.rb:63&lt;/a&gt;:in `update'
...more stack trace...

Request Parameters:

{"commit"=&gt;"Update",
 "_method"=&gt;"put",
 "authenticity_token"=&gt;"qezkVq+MNzFuXxFBJ/GaSoh2BNdxM6oF3H7JP5beFFE=",
 "id"=&gt;"1",
 "person"=&gt;{"name"=&gt;"Barack Obama",
 "birthday(2i)"=&gt;"8",
 "birthday(3i)"=&gt;"4",
 "anniversary(1i)"=&gt;"2009",
 "anniversary(2i)"=&gt;"5",
 "anniversary(3i)"=&gt;"22",
 "birthday(1i)"=&gt;"1960"}}
&lt;/pre&gt;

&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  What happened? There are two keys to figuring out what's going on&lt;br&gt;
&lt;/p&gt;
&lt;ol&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;The date_select helper actually sends 3 http parameters to our application &lt;span style="font-family: courier new;"&gt;anniversary(1i)&lt;/span&gt;, &lt;span style="font-family: courier new;"&gt;anniversary(2i)&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;anniversary(3i)&lt;/span&gt;. ActiveRecord must combine those into a single Date before updating the row in the database.&lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;Looking at assign_multiparameter_attributes in active_record/base.rb we see this this comment that talks about combining 3 http parameters into a date type &lt;em&gt;by calling new on the column type&lt;/em&gt;&lt;br&gt;
    &lt;blockquote&gt;
      Instantiates objects for all attribute classes that &lt;b&gt;needs more than one constructor parameter&lt;/b&gt;. This is done by calling new on the column type or aggregation type (through composed_of) object with these parameters.&lt;br&gt;
      So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum, f for Float, s for String, and a for Array. If all the values for a given attribute are empty, the attribute will be set to nil.
    &lt;/blockquote&gt;&lt;br&gt;
  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now we know we're close to the right place and can check the column's return type using script/console&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;pre class="old_code"&gt;
  $ script/console
  Loading development environment (Rails 2.3.2)
  &gt;&gt; Person.columns_hash['birthday']
  =&gt; #
  &gt;&gt; Person.columns_hash['birthday'].klass
  =&gt; &lt;b&gt;Date&lt;/b&gt;
  &gt;&gt; Person.columns_hash['anniversary']
  =&gt; #
  &gt;&gt; Person.columns_hash['anniversary'].klass
  =&gt; &lt;b&gt;String&lt;/b&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  This makes sense. ActiveRecord is treating the anniversary column as a string because that's what it is in the database so is not combining the 3 multiparameter attributes into a Date. What we need to do is override the default ActiveRecord logic and tell it to treat this column as a date. We can write a failing spec&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/../spec_helper&amp;#39;&lt;/span&gt;

&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;should treat anniversary as a Date column&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns_hash&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;anniversary&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;Date&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# &amp;#39;Person should treat anniversary as a Date column&amp;#39; FAILED&lt;/span&gt;
&lt;span class="c1"&gt;# expected: Date,&lt;/span&gt;
&lt;span class="c1"&gt;#      got: String (using ==)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Then take advantage of a trick of Ruby that allows you to extend an object without affecting other instances of its class (see &lt;a href="http://whytheluckystiff.net/ruby/pickaxe/html/classes.html#UB"&gt;PickAxe book's explanation&lt;/a&gt; of this technique). If we lookup the &lt;a href="http://github.com/rails/rails/blob/18eb80ccc7e932f9a6c00462ceaeea648631b120/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb#L51-64"&gt;definition of klass for a column&lt;/a&gt; It is actually very simple to implement our fix with the 5 lines below.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;columns_hash&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;anniversary&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;
      &lt;span class="ss"&gt;:date&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now our tests pass and when we go back to our site and click the Update button and it works.&lt;br&gt;
  &lt;br&gt;
  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_36rptmL_RFc/ShcBLPag4KI/AAAAAAAADSE/neXvP4YCZJE/s1600-h/person_saved.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 231px; height: 166px;" src="http://2.bp.blogspot.com/_36rptmL_RFc/ShcBLPag4KI/AAAAAAAADSE/neXvP4YCZJE/s320/person_saved.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5338737175898939554" name="BLOGGER_PHOTO_ID_5338737175898939554"&gt;&lt;/a&gt;&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/OU4ACMz7l80" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/05/21/how-to-use-dates-in-rails-when-your.html</feedburner:origLink></entry>
 
 <entry>
   <title>Testing AJAX without a browser with Cucumber and Webrat</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/keNlwN5dHyk/testing-ajax-without-browser-with.html" />
   <published>2009-05-06T00:00:00-07:00</published>
   <updated>2009-05-06T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/05/06/testing-ajax-without-browser-with</id>
   <content type="html">&lt;p&gt;
  I have lately fallen in love with using Cucumber and Webrat for my integration/acceptance testing. &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt; because it allows non-technical people to write or at least read the test scenarios and &lt;a href="http://github.com/brynary/webrat/tree/master"&gt;Webrat&lt;/a&gt; because it matches content and encourages you to write integration tests without relying on xpath to find html elements. The way I like to use these tools is to run Rails integration tests which means its fast since I don’t need to start a mongrel or fire up a browser and can use Rails’ transactional fixtures to rollback all my database changes at the end of each test scenario. The only downside is that you can’t test javascript.&lt;br&gt;
  &lt;br&gt;
  Today I am going to talk about how to get around this and test a form with an ajax autocomplete field. I've built a sample application with all the code examples here and you can download it from &lt;a href="http://github.com/alexrothenberg/testing-ajax-example"&gt;http://github.com/alexrothenberg/testing-ajax-example&lt;/a&gt; if you like. The application I'm building is just some simple app created with scaffolding that just has a User resource with a name and address. I modified the /users page to not display all users but include the auto_complete typeahead to let you pick a user (imagining there may be a lot) so the page looks something like this.&lt;br&gt;
  &lt;br&gt;
  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_36rptmL_RFc/SgG3eqE-W3I/AAAAAAAADOw/7p-_x0l6qLo/s1600-h/search_for_a_user_screen.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 157px;" src="http://4.bp.blogspot.com/_36rptmL_RFc/SgG3eqE-W3I/AAAAAAAADOw/7p-_x0l6qLo/s320/search_for_a_user_screen.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5332745171102489458" name="BLOGGER_PHOTO_ID_5332745171102489458"&gt;&lt;/a&gt;&lt;br&gt;
  &lt;br&gt;
  My first test scenario will ignore the ajax and just test the form which is super easy and can be done by writing a single feature file.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="Gherkin"&gt;&lt;span class="c"&gt;#features/find_a_user.feature&lt;/span&gt;
&lt;span class="nc"&gt;Feature:&lt;/span&gt;&lt;span class="no"&gt; Allow anyone to find a user and see their details&lt;/span&gt;&lt;span class="nb"&gt;&lt;/span&gt;
&lt;span class="nb"&gt;  In order to handle a large set of users&lt;/span&gt;
&lt;span class="nb"&gt;  I want search with autocomplete&lt;/span&gt;
 
  &lt;span class="nc"&gt;Scenario:&lt;/span&gt;&lt;span class="no"&gt; View a candidate detail page without testing ajax&lt;/span&gt;
&lt;span class="k"&gt;    Given &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;When &lt;/span&gt;I am on the homepage
      &lt;span class="k"&gt;And &lt;/span&gt;I fill in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;
      &lt;span class="k"&gt;And &lt;/span&gt;I press &lt;span class="s"&gt;&amp;quot;Find&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;Then &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;
      &lt;span class="k"&gt;And &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  I run it it all passes and I get&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="Gherkin"&gt;$ rake features
(in /Users/alexrothenberg/ruby/testing-ajax-example)
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I &lt;span class="s"&gt;&amp;quot;/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/lib:lib&amp;quot;&lt;/span&gt; 
&lt;span class="s"&gt;&amp;quot;/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/bin/cucumber&amp;quot;&lt;/span&gt; --format pretty --require features/step_definitions/user_steps.rb 
--require features/step_definitions/webrat_steps.rb --require features/support/env.rb --require features/support/paths.rb 
features/find_a_user.feature
&lt;span class="nc"&gt;Feature:&lt;/span&gt;&lt;span class="no"&gt; Allow anyone to find a user and see their details&lt;/span&gt;&lt;span class="nb"&gt;&lt;/span&gt;
&lt;span class="nb"&gt;  In order to handle a large set of users &lt;/span&gt;
&lt;span class="nb"&gt;  I want search with autocomplete&lt;/span&gt;

  &lt;span class="nc"&gt;Scenario:&lt;/span&gt;&lt;span class="no"&gt; View a candidate detail page without testing ajax     # features/find_a_user.feature:5&lt;/span&gt;
&lt;span class="k"&gt;    Given &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;    &lt;span class="c"&gt;# features/step_definitions/user_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;When &lt;/span&gt;I am on the homepage                                     &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:6&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I fill in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;                &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:22&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I press &lt;span class="s"&gt;&amp;quot;Find&amp;quot;&lt;/span&gt;                                            &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:14&lt;/span&gt;
    &lt;span class="k"&gt;Then &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;                              &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;                            &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;

1 scenario (1 passed)
6 steps (6 passed)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  I makes use of the default webrat steps that cucumber gives you for free in features/steps/webrat_steps.rb so I don’t even have to write any code to get it to pass but I still haven’t tested any of my code that responds to the autocomplete request. I’d like my test to verify that my routes, controller and model will all work together. So, I write another scenario and run it and this time it fails because I haven't defined the typeahead steps for the typeahead lines.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="Gherkin"&gt;&lt;span class="c"&gt;#first scenario omitted&lt;/span&gt;

&lt;span class="nc"&gt;Scenario:&lt;/span&gt;&lt;span class="no"&gt; View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13&lt;/span&gt;
&lt;span class="k"&gt;    Given &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;      &lt;span class="c"&gt;# features/step_definitions/user_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;When &lt;/span&gt;I am on the homepage                                       &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:6&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I typeahead in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;             &lt;span class="c"&gt;# features/find_a_user.feature:16&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I fill in &lt;span class="s"&gt;&amp;quot;Which candidate&amp;quot;&lt;/span&gt; with the first typeahead result &lt;span class="c"&gt;# features/find_a_user.feature:17&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I press &lt;span class="s"&gt;&amp;quot;Find&amp;quot;&lt;/span&gt;                                              &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:14&lt;/span&gt;
    &lt;span class="k"&gt;Then &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;                                &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;                              &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;

2 scenarios (1 undefined, 1 passed)
13 steps (3 skipped, 2 undefined, 8 passed)

You can implement step definitions for undefined steps with these snippets:

&lt;span class="k"&gt;When &lt;/span&gt;/^I typeahead in &lt;span class="s"&gt;&amp;quot;([^\&amp;quot;&lt;/span&gt;]*)&lt;span class="s"&gt;&amp;quot; with &amp;quot;&lt;/span&gt;([^\&lt;span class="s"&gt;&amp;quot;]*)&amp;quot;&lt;/span&gt;$/ do |arg1, arg2|
  pending
end

&lt;span class="k"&gt;When &lt;/span&gt;/^I fill in &lt;span class="s"&gt;&amp;quot;([^\&amp;quot;&lt;/span&gt;]*)&lt;span class="s"&gt;&amp;quot; with the first typeahead result$/ do |arg1|&lt;/span&gt;
&lt;span class="s"&gt;  pending&lt;/span&gt;
&lt;span class="s"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now I take the hints cucumber has given me and write my autocomplete steps. The interesting thing here is that I need to leave the response object unchanged so I can fill in the form field after running the typeahead step so I can't use the existing webrat steps as they work on a single pair of request and response objects. So I knew I'd be creating a new class with its own request and response that could be used without affecting the one used by my other cucumber steps. Using good outside-in development practices I deferred thinking about how to do that and first wrote my steps file to look something like this. One interesting thing to notice here is that you can invoke a step from inside another step just by omitting the block as I do in the second step.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="Gherkin"&gt;&lt;span class="k"&gt;When &lt;/span&gt;/^I typeahead in &lt;span class="s"&gt;&amp;quot;(.*)&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;(.*)&amp;quot;&lt;/span&gt;$/ do |field, value|
  field = field_labeled field
  &lt;span class="nn"&gt;@typeahead&lt;/span&gt; = AutoCompleteStepHelper.new(request)
  &lt;span class="nn"&gt;@typeahead.type(field,&lt;/span&gt; value)
end

&lt;span class="k"&gt;When &lt;/span&gt;/^I fill in &lt;span class="s"&gt;&amp;quot;(.*)&amp;quot;&lt;/span&gt; with the first typeahead result$/ do |field|
  &lt;span class="k"&gt;When &lt;/span&gt;%Q[I fill in &lt;span class="s"&gt;&amp;quot;#{field}&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;#{@typeahead.items.first}&amp;quot;&lt;/span&gt;]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now when run the feature again it fails telling me I haven’t yet built the AutoCompleteStepHelper.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="Gherkin"&gt;&lt;span class="c"&gt;#first scenario omitted&lt;/span&gt;

&lt;span class="nc"&gt;Scenario:&lt;/span&gt;&lt;span class="no"&gt; View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13&lt;/span&gt;
&lt;span class="k"&gt;    Given &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;      &lt;span class="c"&gt;# features/step_definitions/user_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;When &lt;/span&gt;I am on the homepage                                       &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:6&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I typeahead in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;             &lt;span class="c"&gt;# features/step_definitions/autocomplete_steps.rb:1&lt;/span&gt;
      uninitialized constant AutoCompleteStepHelper (NameError)
      ./features/step_definitions/autocomplete_steps.rb:3:in `/^I typeahead in &lt;span class="s"&gt;&amp;quot;(.*)&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;(.*)&amp;quot;&lt;/span&gt;$/&amp;#39;
      features/find_a_user.feature:16:in `And I typeahead in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;&amp;#39;
    &lt;span class="k"&gt;And &lt;/span&gt;I fill in &lt;span class="s"&gt;&amp;quot;Which candidate&amp;quot;&lt;/span&gt; with the first typeahead result &lt;span class="c"&gt;# features/step_definitions/autocomplete_steps.rb:7&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I press &lt;span class="s"&gt;&amp;quot;Find&amp;quot;&lt;/span&gt;                                              &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:14&lt;/span&gt;
    &lt;span class="k"&gt;Then &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;                                &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;                              &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;

2 scenarios (1 failed, 1 passed)
13 steps (1 failed, 4 skipped, 8 passed)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  So the next step is to write the AutoCompleteStepHelper class. This class’ job is to have its own request and response that will not affect the ones used by cucumber for the main page requests. It turns out that I can do this by having my class extend ActionController::IntegrationTest and I can even use webrat methods in it because webrat &lt;a href="http://github.com/brynary/webrat/blob/481bfe03c0829a7d858443ceb6a51e1587a0d931/lib/webrat/rails.rb#L100-105"&gt;adds its methods to IntegrationTest&lt;/a&gt;. In this example I'm calling &lt;span style="font-family: courier new;"&gt;visit&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;current_dom&lt;/span&gt; and using &lt;a href="http://nokogiri.rubyforge.org/nokogiri/"&gt;nokogiri&lt;/a&gt; to parse the dom. It is a little weird that I'm subclassing IntegrationTest but this class is not a TestUnit class itself but I decided that was okay.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AutoCompleteStepsHelper&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;IntegrationTest&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existing_request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@controller_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;existing_request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:controller&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="vi"&gt;@controller_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@controller_name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;camelize&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;Controller&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;constantize&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Can&amp;#39;t determine controller class for &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@controller_class_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@controller_class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt;

    &lt;span class="vi"&gt;@controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@controller_class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
    &lt;span class="vi"&gt;@request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TestRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
    &lt;span class="vi"&gt;@response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TestResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
    &lt;span class="vi"&gt;@response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
 
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="n"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:controller&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="vi"&gt;@controller_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:action&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;auto_complete_for_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
 
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;items&lt;/span&gt;
    &lt;span class="n"&gt;current_dom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;//ul/li&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:inner_html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now when I run the feature it all passes.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="Gherkin"&gt;&lt;span class="c"&gt;#first scenario omitted&lt;/span&gt;

  &lt;span class="nc"&gt;Scenario:&lt;/span&gt;&lt;span class="no"&gt; View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13&lt;/span&gt;
&lt;span class="k"&gt;    Given &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;      &lt;span class="c"&gt;# features/step_definitions/user_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;When &lt;/span&gt;I am on the homepage                                       &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:6&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I typeahead in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;             &lt;span class="c"&gt;# features/step_definitions/autocomplete_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I fill in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with the first typeahead result      &lt;span class="c"&gt;# features/step_definitions/autocomplete_steps.rb:7&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I press &lt;span class="s"&gt;&amp;quot;Find&amp;quot;&lt;/span&gt;                                              &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:14&lt;/span&gt;
    &lt;span class="k"&gt;Then &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;                                &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;                              &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;

2 scenarios (2 passed)
13 steps (13 passed)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  The last step I took was to test that the list returned in the typeahead was correct. I created another scenario in my feature.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="Gherkin"&gt;&lt;span class="nc"&gt;Scenario:&lt;/span&gt;&lt;span class="no"&gt; Typeahead should return 2 users that match but not a third&lt;/span&gt;
&lt;span class="k"&gt;    Given &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;
      &lt;span class="k"&gt;And &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Donald Duck&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Pond Lane&amp;quot;&lt;/span&gt;
      &lt;span class="k"&gt;And &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Minnie Mouse&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Disney Avenue&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;When &lt;/span&gt;I am on the homepage
      &lt;span class="k"&gt;And &lt;/span&gt;I typeahead in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;Mi&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;Then &lt;/span&gt;I should see in my typeahead &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;
      &lt;span class="k"&gt;And &lt;/span&gt;I should see in my typeahead &lt;span class="s"&gt;&amp;quot;Minnie Mouse&amp;quot;&lt;/span&gt;
      &lt;span class="k"&gt;And &lt;/span&gt;I should not see in my typeahead &lt;span class="s"&gt;&amp;quot;Donald Duck&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  and I added two new steps&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="Gherkin"&gt;&lt;span class="k"&gt;Then &lt;/span&gt;/^I should see in my typeahead &lt;span class="s"&gt;&amp;quot;(.*)&amp;quot;&lt;/span&gt;$/ do |text|
  &lt;span class="nn"&gt;@typeahead.response_body.should&lt;/span&gt; =~ /&lt;span class="c"&gt;#{text}/m&lt;/span&gt;
end

&lt;span class="k"&gt;Then &lt;/span&gt;/^I should not see in my typeahead &lt;span class="s"&gt;&amp;quot;(.*)&amp;quot;&lt;/span&gt;$/ do |text|
  &lt;span class="nn"&gt;@typeahead.response_body.should_not&lt;/span&gt; =~ /&lt;span class="c"&gt;#{text}/m&lt;/span&gt;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now when I run my features all 3 scenarios are passing&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="Gherkin"&gt;$ rake features
(in /Users/alexrothenberg/ruby/testing-ajax-example)
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I &lt;span class="s"&gt;&amp;quot;/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/lib:lib&amp;quot;&lt;/span&gt; 
&lt;span class="s"&gt;&amp;quot;/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/bin/cucumber&amp;quot;&lt;/span&gt; --format pretty --require features/step_definitions/autocomplete_steps.rb 
--require features/step_definitions/user_steps.rb --require features/step_definitions/webrat_steps.rb 
--require features/support/autocomplete_steps_helper.rb --require features/support/env.rb --require features/support/paths.rb 
features/find_a_user.feature

&lt;span class="nc"&gt;Feature:&lt;/span&gt;&lt;span class="no"&gt; Allow anyone to find a user and see their details&lt;/span&gt;&lt;span class="nb"&gt;&lt;/span&gt;
&lt;span class="nb"&gt;  In order to handle a large set of users &lt;/span&gt;
&lt;span class="nb"&gt;  I want search with autocomplete&lt;/span&gt;

  &lt;span class="nc"&gt;Scenario:&lt;/span&gt;&lt;span class="no"&gt; View a candidate detail page without testing ajax  # features/find_a_user.feature:5&lt;/span&gt;
&lt;span class="k"&gt;    Given &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt; &lt;span class="c"&gt;# features/step_definitions/user_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;When &lt;/span&gt;I am on the homepage                                  &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:6&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I fill in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;             &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:22&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I press &lt;span class="s"&gt;&amp;quot;Find&amp;quot;&lt;/span&gt;                                         &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:14&lt;/span&gt;
    &lt;span class="k"&gt;Then &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;                           &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;                         &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;

  &lt;span class="nc"&gt;Scenario:&lt;/span&gt;&lt;span class="no"&gt; View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13&lt;/span&gt;
&lt;span class="k"&gt;    Given &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;      &lt;span class="c"&gt;# features/step_definitions/user_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;When &lt;/span&gt;I am on the homepage                                       &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:6&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I typeahead in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;             &lt;span class="c"&gt;# features/step_definitions/autocomplete_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I fill in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with the first typeahead result      &lt;span class="c"&gt;# features/step_definitions/autocomplete_steps.rb:7&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I press &lt;span class="s"&gt;&amp;quot;Find&amp;quot;&lt;/span&gt;                                              &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:14&lt;/span&gt;
    &lt;span class="k"&gt;Then &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;                                &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I should see &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;                              &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:93&lt;/span&gt;

  &lt;span class="nc"&gt;Scenario:&lt;/span&gt;&lt;span class="no"&gt; Typeahead should return 2 users that match but not a third # features/find_a_user.feature:22&lt;/span&gt;
&lt;span class="k"&gt;    Given &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;         &lt;span class="c"&gt;# features/step_definitions/user_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Donald Duck&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Pond Lane&amp;quot;&lt;/span&gt;              &lt;span class="c"&gt;# features/step_definitions/user_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Minnie Mouse&amp;quot;&lt;/span&gt; is a user living at &lt;span class="s"&gt;&amp;quot;123 Disney Avenue&amp;quot;&lt;/span&gt;         &lt;span class="c"&gt;# features/step_definitions/user_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;When &lt;/span&gt;I am on the homepage                                          &lt;span class="c"&gt;# features/step_definitions/webrat_steps.rb:6&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I typeahead in &lt;span class="s"&gt;&amp;quot;Which user&amp;quot;&lt;/span&gt; with &lt;span class="s"&gt;&amp;quot;Mi&amp;quot;&lt;/span&gt;                          &lt;span class="c"&gt;# features/step_definitions/autocomplete_steps.rb:1&lt;/span&gt;
    &lt;span class="k"&gt;Then &lt;/span&gt;I should see in my typeahead &lt;span class="s"&gt;&amp;quot;Mickey Mouse&amp;quot;&lt;/span&gt;                   &lt;span class="c"&gt;# features/step_definitions/autocomplete_steps.rb:16&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I should see in my typeahead &lt;span class="s"&gt;&amp;quot;Minnie Mouse&amp;quot;&lt;/span&gt;                    &lt;span class="c"&gt;# features/step_definitions/autocomplete_steps.rb:16&lt;/span&gt;
    &lt;span class="k"&gt;And &lt;/span&gt;I should not see in my typeahead &lt;span class="s"&gt;&amp;quot;Donald Duck&amp;quot;&lt;/span&gt;                 &lt;span class="c"&gt;# features/step_definitions/autocomplete_steps.rb:20&lt;/span&gt;

3 scenarios (3 passed)
21 steps (21 passed)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  What I've done is not full javascript testing (for that I'm planning to look into &lt;a href="http://blog.thinkrelevance.com/2009/4/30/javascript-testing-at-railsconf"&gt;Blue-Ridge&lt;/a&gt; from Relevance). This technique does allow you to test ajax (skipping the "J") without a browser.
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/keNlwN5dHyk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/05/06/testing-ajax-without-browser-with.html</feedburner:origLink></entry>
 
 <entry>
   <title>Managing the draw of a single-elimination tournament</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/FDzmz2Ruevw/managing-draw-of-single-elimination.html" />
   <published>2009-03-30T00:00:00-07:00</published>
   <updated>2009-03-30T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/03/30/managing-draw-of-single-elimination</id>
   <content type="html">My company has been running a &lt;a href="http://en.wikipedia.org/wiki/Go_%28board_game%29"&gt;GO&lt;/a&gt; tournament and since its around NCAA March Madness time I thought it'd be easy to find a site to manage the draw.  I looked but couldn't find anything that did what I wanted so I wrote my own.  Caveat: I just spent a few days on this and it could stand to be enhanced with more features and a rewrite of the ui implementation but I'm open to suggestions if anyone finds this useful.&lt;br /&gt;&lt;br /&gt;To use it &lt;br /&gt;&lt;ol&gt;&lt;br /&gt; &lt;li&gt;Edit the file lib/names.txt with a the players in your tournament&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Run 'rake create_tournament&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Now when you view the site you'll see a draw that looks something like this.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_36rptmL_RFc/SdDfviojZMI/AAAAAAAADNw/U1bcraUPbAU/s1600-h/tournament-draw.png"&gt;&lt;img style="cursor: pointer; width: 232px; height: 320px;" src="http://4.bp.blogspot.com/_36rptmL_RFc/SdDfviojZMI/AAAAAAAADNw/U1bcraUPbAU/s320/tournament-draw.png" alt="" id="BLOGGER_PHOTO_ID_5318997167768298690" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For games with 2 players - all first round games and games where the previous round winners have been determined - you'll be able to click the link and set which player won.&lt;br /&gt;&lt;br /&gt;This was all very quickly thrown together but if you're interested in hosting any sort of single-elimination tournament check it out on github &lt;a href="http://github.com/alexrothenberg/tournament-draw/"&gt;tournament-draw&lt;/a&gt;.  &lt;br /&gt;&lt;br /&gt;Let me know if you use it and how you'd like to enhance it from the quick application it is today.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-5524234857417099518?l=www.alexrothenberg.com' alt='' /&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/FDzmz2Ruevw" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/03/30/managing-draw-of-single-elimination.html</feedburner:origLink></entry>
 
 <entry>
   <title>Link: Search Engine in 200 lines of Ruby Code</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/42Z0hxthvPg/lines-of-ruby.html" />
   <published>2009-03-22T00:00:00-07:00</published>
   <updated>2009-03-22T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/03/22/lines-of-ruby</id>
   <content type="html">I read a very interesting article by someone who works for Yahoo about how he wrote a basic search engine in Ruby in just a few files.  I wouldn't use this for a production system for as an example of how search engines work its fascinating and I plan to keep following his site to see how he enhances it&lt;br /&gt;&lt;br /&gt;Description: &lt;a href="http://blog.saush.com/2009/03/write-an-internet-search-engine-with-200-lines-of-ruby-code/"&gt;http://blog.saush.com/2009/03/write-an-internet-search-engine-with-200-lines-of-ruby-code/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Source: &lt;a href="http://github.com/sausheong/saushengine"&gt;http://github.com/sausheong/saushengine&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;... and he's got a really cool css/javascript formatter for the source in his blog.  I've gotta learn more about &lt;a href="http://alexgorbatchev.com/wiki/SyntaxHighlighter"&gt;SyntaxHighlighter&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-5843513361467282898?l=www.alexrothenberg.com' alt='' /&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/42Z0hxthvPg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/03/22/lines-of-ruby.html</feedburner:origLink></entry>
 
 <entry>
   <title>Using scopes in auto_complete plugin</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/AslJGDPfi0Y/using-scopes-in-autocomplete-plugin.html" />
   <published>2009-03-18T00:00:00-07:00</published>
   <updated>2009-03-18T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/03/18/using-scopes-in-autocomplete-plugin</id>
   <content type="html">&lt;p&gt;
  My colleague &lt;a href="http://patshaughnessy.net"&gt;Pat Shaughnessy&lt;/a&gt; has spent a lot of time recently enhancing the auto_complete plugin. I suggest you read his blog posts and check out his &lt;a href="http://github.com/patshaughnessy/auto_complete"&gt;fork of auto_complete on github&lt;/a&gt; to see the details.&lt;br&gt;
  &lt;br&gt;
  I was reading his latest change to allow &lt;a href="http://patshaughnessy.net/2009/3/14/filtering-auto_complete-pick-lists"&gt;filtering of auto complete picklists&lt;/a&gt; and really like what he did but thought there was one thing that didn't quite feel right - the fact that you have to mix the application logic to filter the list with the plugin logic to find the list in the block in your controller.&lt;br&gt;
  &lt;br&gt;
  Here's the code Pat wrote in his controller and what I'd like to avoid is having to re-implement the "LOWER(tasks.name) LIKE ?" portion that's already implemented in the filtered_auto_complete_for method of autocomplete.rb in the plugin.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;# For task name auto complete, only display tasks&lt;/span&gt;
&lt;span class="c1"&gt;# that belong to the given project: &lt;/span&gt;
&lt;span class="n"&gt;filtered_auto_complete_for&lt;/span&gt; &lt;span class="ss"&gt;:task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;find_options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;find_options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="ss"&gt;:include&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;LOWER(tasks.name) LIKE ? AND projects.name = ?&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;task&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;downcase&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;project&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;:order&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tasks.name ASC&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  I'd like to propose a slight modification so the block you write as part of your application can focus just on the filtering and leave the responsibility for the search with plugin. I'm also proposing we use scopes (which I don't think were around when the original auto_complete plugin was written) to filter and sort the list the plugin. Here is the code I'd like to write in my application.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProjectController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="c1"&gt;# For task name auto complete, only display tasks&lt;/span&gt;
  &lt;span class="c1"&gt;# that belong to the given project: &lt;/span&gt;
  &lt;span class="n"&gt;filtered_auto_complete_for&lt;/span&gt; &lt;span class="ss"&gt;:task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;by_project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;project&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Project&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;named_scope&lt;/span&gt; &lt;span class="ss"&gt;:by_project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
              &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;project_id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:project_id&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;project_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  We can do this with a simple modification of the plugin implementation of filtered_auto_complete_for&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filtered_auto_complete_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;define_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;auto_complete_for_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;find_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="ss"&gt;:conditions&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;LOWER(&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) LIKE ?&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;downcase&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="ss"&gt;:order&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ASC&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;:limit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="vi"&gt;@items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;camelize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;constantize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scoped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;find_options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;block_given?&lt;/span&gt;

    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:inline&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;%= auto_complete_result @items, &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39; %&amp;gt;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Originally, it used passed the find_options hash to the block and then executed the search in one step as "@items = object.to_s.camelize.constantize.find(:all, find_options)". My change is to rely on ActiveRecord proxy objects to chain criteria together leaving the block independent of the criteria here in the plugin. The best part is you don't have to worry about performance as ActiveRecord will intelligently combine the criteria into a single SQL request. For example searching for tasks that start with 'tas' within project #7&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt; User Load (1.2ms)   SELECT * FROM `tasks` WHERE ((`tasks`.`project_id` = '7') AND (LOWER(name) LIKE '%tas%'))  ORDER BY name ASC LIMIT 10&lt;br&gt;
&lt;/pre&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/AslJGDPfi0Y" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/03/18/using-scopes-in-autocomplete-plugin.html</feedburner:origLink></entry>
 
 <entry>
   <title>Java as a Legacy Language</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/bNGXdUNJ-4g/java-as-legacy-language.html" />
   <published>2009-03-18T00:00:00-07:00</published>
   <updated>2009-03-18T00:00:00-07:00</updated>
   <id>http://www.alexrothenberg.com/2009/03/18/java-as-legacy-language</id>
   <content type="html">I came across this article titled &lt;a href="http://asserttrue.blogspot.com/2009/03/java-as-legacy-language.html"&gt;Java as Legacy Language&lt;/a&gt; today.  As an ex-Java guy who is now committed to Ruby I was amused by the title but also think he makes a good point.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;One thing is for sure: If you're in the software development business, don't cling to old ways of doing development. And also, don't get too carried away thinking that something like Scrum is going to be the Bandaid that fixes your agility problems, because it may turn out that your main problem is Java itself. Keep an open mind. Try new things. Be ready when the next disruption arrives, or you may find yourself without a chair when the music stops. &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I don't think Java is "bad" but I do think it encourages you to write big, complicated applications to solve big, complicated problems.  In contrast I find Rails encourages you to realize most of the apps we write are in fact fairly simple and do the same CRUD steps over and over.  Having so much support for that built into the framework helps you think about what's "interesting" about your appplication which may be unique but is probably not big.&lt;br /&gt;&lt;br /&gt;Add to this how easy it is to test in Rails - tools like RSpec &amp; Shoulda, mocking tools, integration testing and more recently cucumber + webrat all make it easier to practice TDD than not to.  While there are tools in Java, the fact that they're harder to use, I believe, means fewer developers will use them and these practices will remain less ingrained in that community.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-4348459139798160542?l=www.alexrothenberg.com' alt='' /&gt;&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/bNGXdUNJ-4g" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/03/18/java-as-legacy-language.html</feedburner:origLink></entry>
 
 <entry>
   <title>Microsoft Office links causing InvalidAuthenticityToken in Rails</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/q_QX1XsydUY/microsoft-office-links-causing.html" />
   <published>2009-03-04T00:00:00-08:00</published>
   <updated>2009-03-04T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2009/03/04/microsoft-office-links-causing</id>
   <content type="html">  &lt;p&gt;
    I started receiving a lot of error notifications recently from my ExceptionNotfier plugin for an error with ActionController::InvalidAuthenticityToken. It turned out the error was occurring because one of my users was pasting a link to my app in an MS Office document and when Office sees the link it makes a request that Rails could not handle. Here I'll show you a simple fix you can use to avoid these errors with much credit going to an article at &lt;a href="http://rails.learnhub.com/lesson/2318-dealing-with-microsoft-office-protocol-discovery-in-rails"&gt;&lt;br&gt;
    Dealing with Microsoft Office Protocol Discovery in Rails&lt;br&gt;&lt;/a&gt;.&lt;br&gt;
    &lt;br&gt;
    My execptions looked something like this (lots of boring details omitted)&lt;br&gt;
    &lt;br&gt;
  &lt;/p&gt;
  &lt;pre class="old_code"&gt;
&lt;br&gt;A ActionController::InvalidAuthenticityToken occurred in events#1164:&lt;br&gt;&lt;br&gt;  ActionController::InvalidAuthenticityToken&lt;br&gt;  [RAILS_ROOT]/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb:86:in `verify_authenticity_token'&lt;br&gt;&lt;br&gt;-------------------------------&lt;br&gt;Environment:&lt;br&gt;-------------------------------&lt;br&gt;  * HTTP_USER_AGENT        : Microsoft Data Access Internet Publishing Provider Protocol Discovery&lt;br&gt;  * REQUEST_METHOD         : OPTIONS&lt;br&gt;
&lt;/pre&gt;
  &lt;p&gt;
    &lt;br&gt;
    &lt;br&gt;
    The problem is that Rails doesn't understand the method 'OPTIONS' (see &lt;a href="http://github.com/rails/rails/blob/ce56c5daa81d61a745b88220014a846a0eea46a4/actionpack/lib/action_controller/routing.rb"&gt;rails/actionpack/lib/action_controller/routing.rb&lt;/a&gt;&lt;br&gt;
    &lt;br&gt;
  &lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;#around line 270 of routing.rb&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ActionController&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Routing&lt;/span&gt;
    &lt;span class="no"&gt;HTTP_METHODS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:put&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:delete&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


  &lt;p&gt;
    &lt;br&gt;
    &lt;br&gt;
    Fixing the problem is fairly simple. You insert a before_filter into your application controller to intercept and handle requests with the option method before the rails code realizes it can't handle the request.&lt;br&gt;
    &lt;br&gt;
  &lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;before_filter&lt;/span&gt; &lt;span class="ss"&gt;:options_for_microsoft_office_protocol_discovery&lt;/span&gt;

  &lt;span class="c1"&gt;### Lots of code omitted&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;options_for_microsoft_office_protocol_discovery&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:nothing&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:status&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:options&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


    &lt;p&gt;
    &lt;br&gt;
    &lt;br&gt;
    Its also easy to write a simple spec in rspec to verify the behavior. There is one trick which is that rails/actionpack/lib/action_controller/test_process.rb defines helper methods for get, post, put, delete &amp;amp; head that we can't use so we need to call the underlying method directly but the signature for that underlying method changed with Rails 2.3 (&lt;a href="http://github.com/rails/rails/commit/6e2a771661a47fb682108648244837f8616e350d"&gt;commit&lt;/a&gt;) so depending what version you're using you'll need one of 2 flavors.&lt;br&gt;
    &lt;br&gt;
  &lt;/p&gt;
  
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="c1"&gt;# Rails 2.3 and above &lt;/span&gt;
&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;should not throw an exception on OPTIONS request (from ms office protocol discovery)&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/any/goofy/path&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;OPTIONS&amp;#39;&lt;/span&gt;
  &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;be_success&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt; 

&lt;span class="c1"&gt;# Rails &amp;lt; 2.3 version&lt;/span&gt;
&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;should not throw an exception on OPTIONS request (from ms office protocol discovery)&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="vi"&gt;@request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;REQUEST_METHOD&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;OPTIONS&amp;#39;&lt;/span&gt;
  &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/any/goofy/path&amp;#39;&lt;/span&gt;
  &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;be_success&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

      
  &lt;p&gt;
    &lt;br&gt;
    &lt;br&gt;
    You can also test from the command line using curl&lt;br&gt;
    &lt;br&gt;
  &lt;/p&gt;
  &lt;pre class="old_code"&gt;
&lt;br&gt;curl -X OPTIONS http://localhost:3000/&lt;br&gt;
&lt;/pre&gt;
  &lt;p&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;span style="font-weight:bold;"&gt;Update:&lt;/span&gt; It turns out that Rails stores the acceptable methods in 2 different places &lt;a href="http://github.com/rails/rails/blob/b1c989f28dd1d619f0e3e3ca1b894b686e517f2f/actionpack/lib/action_controller/request.rb"&gt;actionpack/lib/action_controller/request.rb&lt;/a&gt; which does include all of get head put post delete options and also (see &lt;a href="http://github.com/rails/rails/blob/ce56c5daa81d61a745b88220014a846a0eea46a4/actionpack/lib/action_controller/routing.rb"&gt;rails/actionpack/lib/action_controller/routing.rb&lt;/a&gt; which only includes :get, :head, :post, :put, :delete (options is missing). This means this fix will only work for OPTIONS requests and not any other type as ActionController::Request request_method will throw an exception before getting to the filter code above.
  &lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/q_QX1XsydUY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/03/04/microsoft-office-links-causing.html</feedburner:origLink></entry>
 
 <entry>
   <title>Investigating how Symbol to_proc works</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/nBhBr5fTm8Y/investigating-how-symbol-toproc-works.html" />
   <published>2009-02-07T00:00:00-08:00</published>
   <updated>2009-02-07T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2009/02/07/investigating-how-symbol-toproc-works</id>
   <content type="html">&lt;div&gt;
  One of the things I love about Ruby is how expressive it is and how with open classes it can be optimized to become even more expressive. Since I started using Ruby I don't think I've written a single for or while loop - something I couldn't have imagined saying with any other language! Of course I do this by using iterators and writing code like&lt;br&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="n"&gt;user_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

  
  &lt;br&gt;
  I recently started discovered I could write the same thing even more concisely (as long as I'm using Rails or Ruby 1.9)&lt;br&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="n"&gt;user_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


  &lt;br&gt;
  I decided to investigate how this works.&lt;br&gt;
  &lt;br&gt;
  First I found some good posts by &lt;a href="http://pragdave.pragprog.com/pragdave/2005/11/symbolto_proc.html"&gt;Prag Dave&lt;/a&gt; and &lt;a href="http://railscasts.com/episodes/6"&gt;Ryan Bates&lt;/a&gt; and at &lt;a href="http://www.infoq.com/news/2008/02/to_proc-currying-ruby19"&gt;InfoQ&lt;/a&gt;. This helped but I still didn't understand it all so decided to dig further.&lt;br&gt;
  &lt;br&gt;
  First I took a look at how Rails extends &lt;a href="http://github.com/rails/rails/blob/24ac1d6bdc860d234e70dd4cd4713bd13ac9d40d/activesupport/lib/active_support/core_ext/symbol.rb"&gt;Symbol&lt;/a&gt;&lt;br&gt;
  &lt;br&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="ss"&gt;:to_proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;respond_to?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:to_proc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;
    &lt;span class="c1"&gt;# Turns the symbol into a simple proc, which is especially useful for enumerations. Examples:&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;#   # The same as people.collect { |p| p.name }&lt;/span&gt;
    &lt;span class="c1"&gt;#   people.collect(&amp;amp;:name)&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;#   # The same as people.select { |p| p.manager? }.collect { |p| p.salary }&lt;/span&gt;
    &lt;span class="c1"&gt;#   people.select(&amp;amp;:manager?).collect(&amp;amp;:salary)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_proc&lt;/span&gt;
      &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__send__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;br&gt;
  &lt;br&gt;
  So they defined the &lt;span style="font-family: courier new;"&gt;to_proc&lt;/span&gt; method on symbol and that means the new code will be called when we write &lt;span style="font-family: courier new;"&gt;&amp;amp;:name&lt;/span&gt; because it magically gets transformed into &lt;span style="font-family: courier new;"&gt;:name.to_proc&lt;/span&gt;. I learned something but still needed to learn more to understand how it all works.&lt;br&gt;
  &lt;br&gt;
  Why does the &lt;span style="font-family: courier new;"&gt;&amp;amp;&lt;/span&gt; cause Ruby to call &lt;span style="font-family: courier new;"&gt;to_proc&lt;/span&gt;? I knew that &lt;span style="font-family: courier new;"&gt;&amp;amp;&lt;/span&gt; in the last parameter declaration will pass a provided block as a parameter but this seems to be doing the reverse. Calling a method as an argument but having it interpreted as a block. I tried a couple of experiments in irb&lt;br&gt;
  &lt;br&gt;
  &lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;was_block_given?&lt;/span&gt;
  &lt;span class="nb"&gt;block_given?&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# As expected&lt;/span&gt;
&lt;span class="n"&gt;was_block_given?&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="kp"&gt;true&lt;/span&gt; 
&lt;span class="c1"&gt;# Passing a proc is not the same as having a block&lt;/span&gt;
&lt;span class="n"&gt;was_block_given?&lt;/span&gt; &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="no"&gt;ArgumentError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wrong&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mi"&gt;195&lt;/span&gt;&lt;span class="ss"&gt;:in&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;was_block_given?&amp;#39;&lt;/span&gt;
  &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mi"&gt;195&lt;/span&gt;
  
&lt;span class="c1"&gt;# Prefixing the proc with an &amp;amp;amp; makes it like a block&lt;/span&gt;
&lt;span class="n"&gt;was_block_given?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;amp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


  &lt;br&gt;
  It was not all as I expected but some reading through the &lt;a href="http://www.pragprog.com/titles/ruby/programming-ruby"&gt;PickAxe book&lt;/a&gt; led me to a better understanding. I found this paragraph in the Calling A Method section (page 115 in my copy)&lt;br&gt;
  &lt;br&gt;
  &lt;blockquote&gt;
    If the last argument to a method is preceded by an ampersand, Ruby assumes that it is a Proc object.&lt;br&gt;
    It removes it from the parameter list, converts the Proc object into a block, and associates it with the method.&lt;br&gt;
  &lt;/blockquote&gt;&lt;br&gt;
  &lt;br&gt;
  Ok so now I know why when Ruby sees &lt;span style="font-family: courier new;"&gt;User.all.collect(&amp;amp;:name)&lt;/span&gt; it invokes the &lt;span style="font-family: courier new;"&gt;collect&lt;/span&gt; method with &lt;span style="font-family: courier new;"&gt;name.to_proc&lt;/span&gt; as a block. Next, it was time to figure out why the code Rails put in the to_proc method worked. I took a look at the &lt;a href="http://github.com/evanphx/rubinius/blob/83ab3fd8b6645ac7389e97b5a1969e5eb3b2b038/kernel/common/enumerable.rb"&gt;Rubinius implementation Enumerable&lt;/a&gt;&lt;br&gt;
  &lt;br&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;collect&lt;/span&gt;
  &lt;span class="n"&gt;ary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;block_given?&lt;/span&gt;
    &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ary&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ary&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;ary&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

  &lt;br&gt;
  Again I decided to experiment with irb to see what each part of the to_proc implementation was doing. First I redefined the Symbol to_proc again with a puts so I could confirm what was going on.&lt;br&gt;
  &lt;br&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;
  &lt;span class="c1"&gt;# Turns the symbol into a simple proc, which is especially useful for enumerations. Examples:&lt;/span&gt;
  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;#   # The same as people.collect { |p| p.name }&lt;/span&gt;
  &lt;span class="c1"&gt;#   people.collect(&amp;amp;:name)&lt;/span&gt;
  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;#   # The same as people.select { |p| p.manager? }.collect { |p| p.salary }&lt;/span&gt;
  &lt;span class="c1"&gt;#   people.select(&amp;amp;:manager?).collect(&amp;amp;:salary)&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_proc&lt;/span&gt;
    &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;to_proc args: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
      &lt;span class="n"&gt;args_shift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shift&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;to_proc: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;args_shift&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.__send__(&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, *&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;
      &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args_shift&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__send__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;to_proc result: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
      &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Make the call and see what happens&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:to_s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# to_proc args: [1]&lt;/span&gt;
&lt;span class="c1"&gt;# to_proc: 1.__send__(:to_s, *[])&lt;/span&gt;
&lt;span class="c1"&gt;# to_proc result: &amp;quot;1&amp;quot;&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; [&amp;quot;1&amp;quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

  &lt;br&gt;
  Its brute force but tells us everything we need to know. As expected &lt;span style="font-family: courier new;"&gt;collect&lt;/span&gt; yields to our proc/block with the element in a variable length argument &lt;span style="font-family: courier new;"&gt;[1]&lt;/span&gt;, it extracts the &lt;span style="font-family: courier new;"&gt;1&lt;/span&gt; and sends it the &lt;span style="font-family: courier new;"&gt;to_s&lt;/span&gt; method with no arguments returning the string &lt;span style="font-family: courier new;"&gt;"1"&lt;/span&gt;. At this point I think I understand how it all works and decide to confirm by running a few more (more complicated) tests in irb&lt;br&gt;
  &lt;br&gt;

  &lt;br&gt;
  It all works as expected and I decide I know as much as I need to about this and call it a day.&lt;br&gt;
  &lt;br&gt;
  So why did I bother figuring all this out and then writing it up? Mostly because I didn't know how it worked and thought there was some 'magic' going on. I could have continued using this feature without understanding how it worked but now that I understand how it works if some need ever arises for me to do some similar magic I know how to go about it. As for writing it up I hope someone else may read this and find it useful but by I increased my own understanding through the act of writing.
  &lt;div class="blogger-post-footer"&gt;
    &lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/86313661235162475-8845862891270009488?l=www.alexrothenberg.com' alt=''&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/nBhBr5fTm8Y" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/02/07/investigating-how-symbol-toproc-works.html</feedburner:origLink></entry>
 
 <entry>
   <title>Maintaining your technical chops is a full time job</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/rC2MxcCi2ic/maintaining-your-technical-chops-is.html" />
   <published>2009-02-05T00:00:00-08:00</published>
   <updated>2009-02-05T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2009/02/05/maintaining-your-technical-chops-is</id>
   <content type="html">&lt;p&gt;
  Great quote from &lt;a href="http://blog.objectmentor.com/articles/2009/01/31/quality-doesnt-matter-that-much-jeff-and-joel"&gt;Uncle Bob&lt;/a&gt; (near the bottom of the post)&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;blockquote&gt;
  I think that maintaining your technical chops is a full time job. For that reason I have avoided becoming a business wonk. I hire people to do that for me so I can keep my technical skills as sharp as possible and remain relevant to my profession. I don’t believe I can offer technical advice unless I am living that technical advice.
&lt;/blockquote&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/rC2MxcCi2ic" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/02/05/maintaining-your-technical-chops-is.html</feedburner:origLink></entry>
 
 <entry>
   <title>Never sacrifice quality for speed!</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/Jdp6pnPI3Eo/never-sacrifice-quality-for-speed.html" />
   <published>2009-02-04T00:00:00-08:00</published>
   <updated>2009-02-04T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2009/02/04/never-sacrifice-quality-for-speed</id>
   <content type="html">&lt;p&gt;
  I just read two really good articles by &lt;a href="http://xprogramming.com/blog/2009/02/01/quality-speed-tradeoff-youre-kidding-yourself/"&gt;Ron Jeffries&lt;/a&gt; and &lt;a href="http://blog.objectmentor.com/articles/2009/02/03/speed-kills"&gt;Uncle Bob&lt;/a&gt; about why sacrificing quality to go faster is always a bad idea.&lt;br&gt;
  &lt;br&gt;
  This is very relevant to me now as I'm working with a sponsor now who thinks that by pushing harder and 'doing it in parallel' he can get everything he wants by the date he wants avoiding any hard decisions involving tradeoffs between scope and date. I have worked on many teams over the years that could speed up without sacrificing quality by focusing on the right things basically by emphasizing working software over high ceremony (pretty much straight from the &lt;a href="http://agilemanifesto.org/"&gt;Agile Manifesto&lt;/a&gt;). However the idea that you can get something out the door quickly without "wasting your time on quality" to me means that the person you're talking to doesn't understand quality. They think quality means &lt;span style="font-style:italic;"&gt;those silly engineering things developers spend their time on&lt;/span&gt; rather than &lt;span style="font-style:italic;"&gt;software that works the way you want and can be reliably enhanced later&lt;/span&gt;.&lt;br&gt;
  &lt;br&gt;
  Somehow we as technologists need to do a better job of explaining to our business sponsors that "quality" is not a technical term!
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/Jdp6pnPI3Eo" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/02/04/never-sacrifice-quality-for-speed.html</feedburner:origLink></entry>
 
 <entry>
   <title>How I refine a test spec while writing getting it to green</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/CxtyvBgT0wY/how-i-refine-test-spec-while-writing.html" />
   <published>2009-01-09T00:00:00-08:00</published>
   <updated>2009-01-09T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2009/01/09/how-i-refine-test-spec-while-writing</id>
   <content type="html">&lt;p&gt;
  In most of the examples I've read on TDD they show the Red-Green-Refactor cycle as&lt;br&gt;
&lt;/p&gt;
&lt;ol&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;Write a failing test
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;Write just enough code to make the test pass
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;Refactor
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;Repeat
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  I absolutely do believe in this cycle and live it every day however I think there's a small detail that differs from what I do. When I move from step 1 to step 2, I keep my test window open and will switch back and forth between the test and code windows and refining the test while writing the code that makes the test pass. Its only as I write the code that I realize what calls I need to mock out in the test which also adds additional expectations to my test. I'm sure this is how most people work but I've never seen it written up so I'm going to try going through an example here.&lt;br&gt;
  &lt;br&gt;
  Let's say I have a social networking application with a page showing friend requests where you can accept or reject each request. Something like this&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;div style="background-color:#F5F6E7"&gt;
  &lt;br&gt;
  Friend Requests:&lt;br&gt;
  &lt;form onclick='return false'&gt;
    &lt;br&gt;
    &lt;input name="approved_requests[]" type="checkbox" value="123"&gt; Accept request from Pat?&lt;br&gt;
    &lt;input name="approved_requests[]" type="checkbox" value="124"&gt; Accept request from Gourav?&lt;br&gt;
  &lt;/form&gt;&lt;br&gt;
&lt;/div&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now I'm ready to implement an action in the Friend Controller that receives a posted form with a list of friend requests to accept and reject. I might first go into my &lt;span style="font-family: courier new;"&gt;friends_controller_spec.rb&lt;/span&gt; and write something like&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;describe FriendController do&lt;br&gt;  it 'should approve one friend requests' do&lt;br&gt;    post :update_requests, :approved_requests =&amp;gt; ['123']&lt;br&gt;    response.should be_redirect&lt;br&gt;    response.should redirect_to(:back)&lt;br&gt;    flash[:notice].should  == "Friend requests approved."&lt;br&gt;  end&lt;br&gt;end&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now I have a failing test so I start implementing the code&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;class FriendController &amp;lt; ApplicationController&lt;br&gt;  def update_requests&lt;br&gt;    FriendRequest.approve(params[:approve_requests])&lt;br&gt;    flash[:notice] = "User access changes saved."&lt;br&gt;    redirect_to :back&lt;br&gt;  end&lt;br&gt;end&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  I'm done but my test is still failing...why? I haven't added the &lt;span style="font-family: courier new;"&gt;approve&lt;/span&gt; method to my &lt;span style="font-family: courier new;"&gt;FriendRequest&lt;/span&gt; model yet. I could go ahead and implement that method to get this test to pass but I don't want to do that because then this test would be testing more than just one unit. This is a unit test for the update_requests method of my FriendController and should be isolated from bugs in the rest of my application. Time to go back to the spec and add a mock to isolate this spec from the model and impose another expectation on my spec (that the method be called with the correct argument).&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;describe FriendController do&lt;br&gt;  it 'should approve one friend requests' do&lt;br&gt;    FriendRequest.expects(:approve).with(['123'])&lt;br&gt;    request.env['HTTP_REFERER'] = "http://some.site.com"&lt;br&gt;  &lt;br&gt;    post :update_requests, :approved_requests =&amp;gt; ['123']&lt;br&gt;    response.should be_redirect&lt;br&gt;    response.should redirect_to(:back)&lt;br&gt;    flash[:notice].should  == "Friend requests approved."&lt;br&gt;  end&lt;br&gt;end&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Now my spec passes and I can do my refactoring then go back to the beginning and write my next expectation.&lt;br&gt;
  &lt;br&gt;
  The point of this example is that when I first wrote the spec I hadn't yet thought about how I would implement update_requests so did not yet know that I would need to mock FriendRequest.approve. I do this all the time and typically find myself go back and forth between the code and spec many times with the spec telling me what code I need to write and the code telling me how to refine the spec.&lt;br&gt;
  &lt;br&gt;
  One last point (and a teaser for a future post). You have probably noticed that although my spec passes if I try to run the application it will not work because I still haven't written the FriendRequest.approve method. In a future post I hope to discuss how to interleave integration testing into this process to ensure that the classes we're writing in isolation also integrate so that the application satisfies its business function.
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/CxtyvBgT0wY" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2009/01/09/how-i-refine-test-spec-while-writing.html</feedburner:origLink></entry>
 
 <entry>
   <title>How I use TDD for  Integration and Isolation testing</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/zfNpMddN9JA/i-read-interesting-post-today-by-david.html" />
   <published>2008-12-11T00:00:00-08:00</published>
   <updated>2008-12-11T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2008/12/11/i-read-interesting-post-today-by-david</id>
   <content type="html">&lt;p&gt;
  I read an interesting post today by David Chelimsky who wrote RSpec &lt;a href="http://blog.davidchelimsky.net/2008/12/11/a-case-against-a-case-against-mocking-and-stubbing"&gt;A case against a case against mocking and stubbing&lt;/a&gt;. Its about mocking in testing and isolated vs integrated tests. I liked it all but what I particularly liked is how it describes the process of &lt;a href="http://kinderman.net/articles/2007/11/18/testing-on-high-bottom-up-versus-top-down-test-driven-development"&gt;outside-in development&lt;/a&gt;.&lt;br&gt;
  &lt;br&gt;
  To quote:&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;ol&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;Write scenarios in plain text with cucumber (driven by user stories, organized in features).
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;Write the code for a step (or part of a step), run the feature, and observe the failure.
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;Optionally (yes, it depends – and why is the topic for another blog) drive out a view with a view spec. When I say “drive out,” I mean a very granular Red/Green/Refactor cycle that only involves this view, and only enough of this view to support satisfaction of the failing step in the cucumber feature.
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;Drive out a controller action using the same, granular Red/Green/Refactor cycle. And it may not be the entire controller action I think I want, covering all the cases I think I want. Just enough to support satisfaction of the failing step.
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;Drive out the parts of the model that I need to satisfy the failing step, using the same granular R/G/R process.
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
  &lt;li&gt;Run the cucumber feature and assess where I am.
  &lt;/li&gt;
  &lt;li style="list-style: none"&gt;
    &lt;br&gt;
  &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  In my projects I think I'm pretty good at following 3,4 &amp;amp;5 but I've struggled with steps 1 &amp;amp; 6. With the advent of &lt;a href="http://github.com/aslakhellesoy/cucumber/wikis"&gt;cucumber&lt;/a&gt; I think now is the time to work on those other steps. I'll let you know how it goes in the New Year.
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/zfNpMddN9JA" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2008/12/11/i-read-interesting-post-today-by-david.html</feedburner:origLink></entry>
 
 <entry>
   <title>Knows which specs are slowing down my spec suite</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/KMkpr3Iglqg/knows-which-specs-are-slowing-down-my.html" />
   <published>2008-12-06T00:00:00-08:00</published>
   <updated>2008-12-06T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2008/12/06/knows-which-specs-are-slowing-down-my</id>
   <content type="html">&lt;p&gt;
  I often watch my specs run with the ........'s marching across my terminal and sometimes it seems to pause as it hits a particularly slow one. I figure there's some poorly written spec that's slowing my entire suite down and I &lt;span style="font-style:italic;"&gt;should&lt;/span&gt; figure out what it is and fix it. But I rarely (if ever) take the time to track down the offender so never fix it. I just discovered that the clever folks writing rspec have taken away my excuse for laziness. I can tell it to report on the slowest specs by putting a line in my spec.opts file telling it to use the ProfileFormatter (see the first line below)&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;--format profile&lt;br&gt;--colour&lt;br&gt;--loadby mtime&lt;br&gt;--reverse&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  For example running the specs on my current project I get this output.&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;Profiling enabled.&lt;br&gt;........(a bunch more dots)&lt;br&gt;&lt;br&gt;Top 10 slowest examples:&lt;br&gt;2.4908950 WikiContent should find all activity for a user&lt;br&gt;0.8061750 WikiContent should find recent activity for a user in last 15 days&lt;br&gt;0.2438460 WikiContent::Version should allow limit on results from finding recent activity&lt;br&gt;0.1821710 User should have a list of owned content&lt;br&gt;0.1700670 WikiContent should find results if access type is not same as role of the user but role of user is 'Leader'&lt;br&gt;0.1593900 ContentsController allows PUT request to 'update' action for 'member' role&lt;br&gt;0.1514150 Search::SearchResponse gets the wiki content id of an asset from the xml response&lt;br&gt;0.1470310 Content should always allow leaders to see all pages&lt;br&gt;0.1394920 Page should delete all comments when destroyed&lt;br&gt;0.1370330 ContentsController should save content and create the uploaded asset on successful POST to the 'create' action&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Over the next few days I will find time to take a look at 'WikiContent find all activity' and 'WikiContent find recent activity' specs as they are the two clear outliers.&lt;br&gt;
  &lt;br&gt;
  I now have no excuse to not optimize my slowest specs because I didn't know which they were!
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/KMkpr3Iglqg" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2008/12/06/knows-which-specs-are-slowing-down-my.html</feedburner:origLink></entry>
 
 <entry>
   <title>Bug/patch with rspec-rails and helper instance variables</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/dmjUVGvohik/bugpatch-with-rspec-rails-and-helper.html" />
   <published>2008-12-06T00:00:00-08:00</published>
   <updated>2008-12-06T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2008/12/06/bugpatch-with-rspec-rails-and-helper</id>
   <content type="html">&lt;p&gt;
  I finally got around to upgrading my version of rspec-rails from one that's almost a year old and came across an issue with the way &lt;a href="http://blog.davidchelimsky.net/2008/5/29/rspec-waving-bye-bye-to-implicit-module-inclusion"&gt;implicit module inclusion&lt;/a&gt; is handled.&lt;br&gt;
  &lt;br&gt;
  If you have a handler that uses memoization to cache some information in instance variables such as this (I'm not sure if this is a smell but my project has some examples of it)&lt;br&gt;
  &lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;module UsersHelper&lt;br&gt; def all_users&lt;br&gt;   @users ||= User.find(:all)&lt;br&gt; end&lt;br&gt;end&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  You would expect this spec to work&lt;br&gt;
&lt;/p&gt;
&lt;pre class="old_code"&gt;
&lt;br&gt;describe UsersHelper do&lt;br&gt; it "should find all users" do&lt;br&gt;   User.expects(:find).with(:all).returns(result=mock)&lt;br&gt;   helper.all_users.should == result&lt;br&gt; end&lt;br&gt;end&lt;br&gt;
&lt;/pre&gt;
&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Sometimes it does but if any other spec has called &lt;span style="font-family: courier new;"&gt;helper.all_users&lt;/span&gt; previously it will fail as the memoized &lt;span style="font-family: courier new;"&gt;@users&lt;/span&gt; variable is not nil so the collection is reused.&lt;br&gt;
  &lt;br&gt;
  I have submitted a &lt;a href="http://rspec.lighthouseapp.com/projects/5645-rspec/tickets/627-rspec-rails-specs-resusing-helper-so-instance-variables-are-side-effects"&gt;lighthouse patch to rspec-rails&lt;/a&gt; that fixes the problem so hopefully they will agree to fix it soon. Until then patch is available on github in &lt;a href="http://github.com/alexrothenberg/rspec-rails/commit/2d38cb9e2a8e2eb407e07e5494382ac2f263aef4"&gt;my fork or rspec-rails&lt;/a&gt; if you want to use it.
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/dmjUVGvohik" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2008/12/06/bugpatch-with-rspec-rails-and-helper.html</feedburner:origLink></entry>
 
 <entry>
   <title>Applications usually use their own data</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/T2PGSn2fsoU/applications-usually-use-their-own-data.html" />
   <published>2008-11-25T00:00:00-08:00</published>
   <updated>2008-11-25T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2008/11/25/applications-usually-use-their-own-data</id>
   <content type="html">&lt;p&gt;
  I just read a very interesting post by Martin Fowler called &lt;a href="http://martinfowler.com/bliki/DatabaseThaw.html"&gt;Database Thaw&lt;/a&gt;. He talks about various database technologies and what the future might hold for object or relational databases but what caught my interest was his discussion of application and database integration patterns.&lt;br&gt;
  &lt;br&gt;
  He says "For many organizations today, the primary pattern for integration is &lt;a href="http://www.eaipatterns.com/SharedDataBaseIntegration.html"&gt;Shared Database Integration&lt;/a&gt; - where multiple applications are integrated by all using a common database." This is certainly true where I work. I've even heard it said that we have one gigantic application since all (or most) share the same underlying database so cannot be updated independently.&lt;br&gt;
  &lt;br&gt;
  He also talks about &lt;a href="http://martinfowler.com/bliki/IntegrationDatabase.html"&gt;Integration Databases&lt;/a&gt; which store data for multiple applications and &lt;a href="http://martinfowler.com/bliki/ApplicationDatabase.html"&gt;Application Databases&lt;/a&gt; which are controlled and accessed by a single application.&lt;br&gt;
  &lt;br&gt;
  Historically my company has moved toward the integration database pattern often building complex service layers to enable shared access to the data on the assumption that if you build it they will come the data would be reused if it was easy enough. However I believe that its only a very small subset of our data that is truly common and many applications want to use. For that small subset a shared database with a service layer is probably a good design. The vast majority is private to an application and by designing it into a separate application database can evolve to best meet the needs of the application without concern for a more general service that in our case is more hindrance than benefit.&lt;br&gt;
  &lt;br&gt;
  One important thing to remember about an application database is that the data exists to meet the needs of the application so a design that allows the database to best meet the application's needs will be to everyone's benefit. Finally database technologies are very complex and do a lot so it is probably wise to have a good database developer on your team to make sure you're using the database appropriately but they should be a part of your team not on a separate database team as I've seen in the past - particularly on Java/Oracle projects I've been a part of.&lt;br&gt;
  &lt;br&gt;
  Thoughts?
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/T2PGSn2fsoU" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2008/11/25/applications-usually-use-their-own-data.html</feedburner:origLink></entry>
 
 <entry>
   <title>Silly site - Netdisaster ... Destroy the Web</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/jKlGk_NkZJk/silly-site-netdisaster-destroy-web.html" />
   <published>2008-11-20T00:00:00-08:00</published>
   <updated>2008-11-20T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2008/11/20/silly-site-netdisaster-destroy-web</id>
   <content type="html">My kids just showed me a silly site &lt;a href="http://www.netdisaster.com/"&gt;http://www.netdisaster.com/&lt;/a&gt; I had to share.
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/jKlGk_NkZJk" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2008/11/20/silly-site-netdisaster-destroy-web.html</feedburner:origLink></entry>
 
 <entry>
   <title>Buy services and Build websites</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/_UfGMWzH0-w/buy-services-and-build-websites.html" />
   <published>2008-11-16T00:00:00-08:00</published>
   <updated>2008-11-16T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2008/11/16/buy-services-and-build-websites</id>
   <content type="html">&lt;p&gt;
  Where I work there's recently been a lot of talk about how to make the decision whether to buy or build software. I've recently concluded that while you can buy a commoditized service you can not buy a website!&lt;br&gt;
  &lt;br&gt;
  What I've seen is people thinking we could "buy" (or download open source) a site but then realize they want to change the branding, adapt the terminology to match our business. combine it with another product or add one extra piece of functionality that the existing site doesn't have. Whatever the APIs provided by the product you're left with custom software written on top of the product you bought. I've seen this with big commercial products like Documentum and open source products like Drupal. I now believe that there's no such thing as "a little" customization and you can only buy a site if you want 0 customization (applying a skin or inserting your logos are acceptable).&lt;br&gt;
  &lt;br&gt;
  This does not mean everyone should develop custom software from scratch. There are tons of opportunities to buy commoditized services and write just a little custom code to glue them together. This allows you to focus on the aspects of your site that are business differentiators (the branding, the terminology, your workflows, your business rules, etc) without fighting the vendor's idea of those things. You don't have to write too much code as what we continually revise upward what we consider a commoditized service (i.e. it used to be document storage and is becoming document management with workflow and security).&lt;br&gt;
  &lt;br&gt;
  The process of creating a blog aggregator as I described in my last post &lt;a href="http://alexrothenberg.blogspot.com/2008/11/blog-aggregator-wayweworkit.html"&gt;I built a Blog Aggregator&lt;/a&gt; showed me how true this is. I used Atom and RSS parsing and generating service which left me just to build a small site with the UI, security and glue holding it all together. Its just a small example but as I look around &lt;a href="http://github.com/"&gt;github&lt;/a&gt; I'm struck that the most interesting packages are plugins and gems for others to use and the less interesting ones are complete sites. This may be a no brainer for the Open Source community but is something that I am just realizing and I think that enterprises and commercial vendors still need to learn.
&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/alexrothenberg/~4/_UfGMWzH0-w" height="1" width="1"/&gt;</content>
 <feedburner:origLink>http://www.alexrothenberg.com/2008/11/16/buy-services-and-build-websites.html</feedburner:origLink></entry>
 
 <entry>
   <title>I built a blog aggregator - waywework.it</title>
   <link href="http://feedproxy.google.com/~r/alexrothenberg/~3/tGOOfg0HTDk/blog-aggregator-wayweworkit.html" />
   <published>2008-11-09T00:00:00-08:00</published>
   <updated>2008-11-09T00:00:00-08:00</updated>
   <id>http://www.alexrothenberg.com/2008/11/09/blog-aggregator-wayweworkit</id>
   <content type="html">&lt;p&gt;
  I've been spending some time recently putting together a blog aggregator site for some of the folks I work with. Its now up and running at &lt;a href="http://waywework.it"&gt;http://waywework.it&lt;/a&gt;. I hope this will be an interesting place to share our public community and as one of my colleagues said "this keeps my Google Reader much neater".&lt;br&gt;
  &lt;br&gt;
  Today I'd like to talk about the code running this site which is posted and available on github at &lt;a href="http://github.com/alexrothenberg/waywework"&gt;http://github.com/alexrothenberg/waywework&lt;/a&gt;.&lt;br&gt;
  &lt;br&gt;
  I started thinking I would use an existing aggregator site and just apply my skin but when I did a quick search on github I most of the hard work existed in atom and rss gems and plugins and I wanted to take advantage of the just released Rails 2.2 so I decided to build my own. This turned out to be not too much work. Today I'd like to talk about how I put this together.&lt;br&gt;
  &lt;br&gt;
  First I created my project with some scaffolding for feeds which would have_many posts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Feed&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:dependent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:delete_all&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:feed&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  I soon found the &lt;a href="http://split-s.blogspot.com/2006/04/atom-10-parser-for-ruby.html"&gt;atom gem&lt;/a&gt; and &lt;a href="http://www.rubyrss.com/"&gt;rss parser&lt;/a&gt; built into ruby. Using them was a piece of cake as all I had to do was create a method to call each one in my Feed model&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Feed&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_posts_from_atom&lt;/span&gt; &lt;span class="n"&gt;atom_xml&lt;/span&gt;
    &lt;span class="n"&gt;feed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Atom&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Feed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;atom_xml&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;detect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rel&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;alternate&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;create_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:contents&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:url&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                  &lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:db&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;:updated&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:db&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blank?&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;  
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_posts_from_rss&lt;/span&gt; &lt;span class="n"&gt;rss_xml&lt;/span&gt;
    &lt;span class="n"&gt;rss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RSS&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rss_xml&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;rss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;create_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:contents&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:url&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                  &lt;span class="ss"&gt;:published&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_formatted_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:db&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;:updated&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_formatted_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:db&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;rss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blank?&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  Of course I had to create the glue wrapping it all together. A rake task to be call on a schedule&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:feeds&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Load the feeds&amp;quot;&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:populate&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;feeds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Feed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;
    &lt;span class="n"&gt;feeds&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_latest&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;br&gt;
  &lt;br&gt;
  and the logic to load the feed, parse it and update the posts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Feed&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_latest&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;getting feed for &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;xml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_feed&lt;/span&gt;
    &lt;span class="n"&gt;got_atom_posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_posts_from_atom&lt;/span&gt; &lt;span class="n"&gt;xml&lt;/span&gt;
    &lt;span class="n"&gt;get_posts_from_rss&lt;/span&gt; &lt;span class="n"&gt;xml&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;got_atom_posts&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_feed&lt;/span&gt;
    &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feed_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_post&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:feed_id&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="n"&gt;existing_post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_by_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:url&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;existing_post&lt;/span&gt;
      &lt;span class="n"&gt;existing_post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_attributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"
