<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Scott Patten's Blog</title>
 <link href="http://scottpatten.ca/atom.xml" rel="self"/>
 <link href="http://scottpatten.ca/blog.html"/>
 <updated>2019-12-20T01:58:30-08:00</updated>
 <id>http://scottpatten.ca/</id>
 <author>
   <name>Scott Patten</name>
   <email>scott@scottpatten.ca</email>
 </author>
 
 
 <entry>
   <title>A Truly Minimum Viable Kitchen</title>
   <link href="http://scottpatten.ca/2014/02/a-truly-minimum-viable-kitchen.html"/>
   <updated>2014-02-24T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2014/02/a-truly-minimum-viable-kitchen</id>
   <content type="html">&lt;p&gt;I read Matt Maroon’s &lt;a href=&quot;http://priceonomics.com/cookware/&quot;&gt;Minimum Viable Kitchen post&lt;/a&gt; (and &lt;a href=&quot;http://news.ycombinator.com/item?id=5038598&quot;&gt;the ensuing Hacker News discussion&lt;/a&gt;) a while ago, and I’ve been thinking about it off and on since then.&lt;/p&gt;

&lt;p&gt;Not about the post per-se, but about what a minimum viable kitchen was, and whether there was anything interesting in the concept.&lt;/p&gt;

&lt;p&gt;In the original post, Matt goes into great detail on a huge list of things that are needed for a Minimum Viable Kitchen. It quickly becomes obvious that Matt is not a minimalist. The list includes things like a stand mixer, a scale, and a 10-piece pot and pan set. Nothing wrong with that. I own a stand mixer and a scale, and I use them all the time, but I certainly wouldn’t put them on my “desert-island kitchen list”. I don’t own 10 pots and pans. I do agree that you need good quality ones, but 10 seems like a bit much, even for a non-minimal kitchen. I’d rather have the extra cupboard space.&lt;/p&gt;

&lt;h2 id=&quot;truly-minimal&quot;&gt;Truly Minimal&lt;/h2&gt;

&lt;p&gt;So, let’s scale it back a bit. What is a truly minimalist kitchen, and what can you make with it?&lt;/p&gt;

&lt;p&gt;I’m going to assume that you are living in a standard house that comes with a fridge, stove and oven. Let’s pretend you are just moving into your first place and have nothing else. What do you need to cook with? I’m going to ignore anything you use to eat, we’re just talking about getting food to the table here.&lt;/p&gt;

&lt;p&gt;Okay how’s this for a first shot.&lt;/p&gt;

&lt;!--more--&gt;

&lt;ol&gt;
  &lt;li&gt;A cutting board&lt;/li&gt;
  &lt;li&gt;A chef’s knife&lt;/li&gt;
  &lt;li&gt;Stuff to sharpen the knife (honing steel and sharpener)&lt;/li&gt;
  &lt;li&gt;A 12” cast-iron frying pan with a lid&lt;/li&gt;
  &lt;li&gt;A medium-sized pot&lt;/li&gt;
  &lt;li&gt;A metal spatula and a metal spoon&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With this and a few ingredients, you can make a lot of great meals.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A simple omelette with cheese, mushrooms and bacon&lt;/li&gt;
  &lt;li&gt;Broccoli and Beef Stir-Fry.&lt;/li&gt;
  &lt;li&gt;Roast Chicken surrounded by Onions and Garlic  (Use the roasted garlic and drippings to make a gravy in the pan when the chicken is done.)&lt;/li&gt;
  &lt;li&gt;Chickpea curry with coconut sauce.&lt;/li&gt;
  &lt;li&gt;Rice pilaf&lt;/li&gt;
  &lt;li&gt;Fajitas&lt;/li&gt;
  &lt;li&gt;A frittata&lt;/li&gt;
  &lt;li&gt;This amazing &lt;a href=&quot;http://www.youtube.com/watch?v=A2M-l2Y8crk&quot;&gt;Puerto Rican style Pork Shoulder&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Pancakes&lt;/li&gt;
  &lt;li&gt;Home-fries&lt;/li&gt;
  &lt;li&gt;Corn Bread&lt;/li&gt;
  &lt;li&gt;Roasted beets on a bed of greens with fresh goat cheese, dressed with olive oil and balsamic vinegar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is about as minimal as I can imagine. It’s almost viable, and probably would be fine for a while.&lt;/p&gt;

&lt;h2 id=&quot;why-bother-with-a-minimal-kitchen-anyways&quot;&gt;Why bother with a minimal kitchen anyways?&lt;/h2&gt;

&lt;p&gt;The whole point of this Minimum Viable Product (oops, sorry, kitchen) thing is to learn and learn quickly. So try this for a while and find out what you’re missing. Use all of your tools and listen carefully to yourself, and you’ll know what you’re missing. Think about what you’re making, what you can’t make that you’re craving, and what about your setup drives you crazy.&lt;/p&gt;

&lt;p&gt;Do that for a while, and (carefully! cautiously!) buy a few things, and you’ll have a truly viable Kitchen.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>No Excuses</title>
   <link href="http://scottpatten.ca/2012/04/no-excuses.html"/>
   <updated>2012-04-23T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2012/04/no-excuses</id>
   <content type="html">&lt;p&gt;I wrote this in response to a post on HN. I could link to the post, but it doesn’t matter. There are posts like this &lt;em&gt;all the time&lt;/em&gt;. Stop making excuses. Go build something.&lt;/p&gt;

&lt;hr /&gt;

&lt;blockquote&gt;
  &lt;p&gt;This is going to sound more dramatic than it was, but here’s one way of summarizing the last five years of my life:&lt;/p&gt;

  &lt;p&gt;I was 35, working at a great job as a physicist. Amazing team (I was usually the dumbest guy in the room), amazing project, but I was bored. I knew that if this didn’t make me happy, I needed to get out. I read a few PG essays, caught the startup bug, and started coding in the evenings.&lt;/p&gt;

  &lt;p&gt;Within 8 months, with a brand-new daughter and another that was two, I was gone from that job, working on my own. In that 8 months I had taught myself web-dev from scratch.&lt;/p&gt;

  &lt;p&gt;I knew nothing of Ruby, HTML, CSS or JavaScript. I had a smattering of Unix knowledge and had been coding data-analysis in Python and C for a while, but the amount I had to learn was staggering. I bought tons of books, learned tons, and (luckily) had no idea how much I still had to learn.&lt;/p&gt;

  &lt;!--more--&gt;
  &lt;p&gt;The first startup idea (online graphing software for physicists – I didn’t exactly reach far for the idea) was a complete flop. That’s okay, though. I turned to consulting for a while. Gave some talks. Wrote part of a book. Met my co-founder by consulting for him for a while.&lt;/p&gt;

  &lt;p&gt;Now, things are good. Leanpub is growing steadily, and I couldn’t be happier.&lt;/p&gt;

  &lt;p&gt;The point is, that you can and should teach yourself some new skills. You’re way closer to being employable than I was, that’s for sure. It may take some evenings and weekends, but they’ll be some of the most fun evening and weekends you ever have. Find something that you want to do and build it. Fall in love with the idea, but be ready to dump it for something better.&lt;/p&gt;

  &lt;p&gt;The market for people with even a smattering of Rails knowledge is huge. iPhone dev is bigger. or Erlang. or fancy JavaScript using Socket.IO.&lt;/p&gt;

  &lt;p&gt;Location doesn’t matter. Age doesn’t matter (I’m 40 now, in Vancouver, not in SV, and I bet I could find 10 jobs at the drop of a hat). My blog isn’t huge. My startup hasn’t had “an exit”.&lt;/p&gt;

  &lt;p&gt;There are excuses, and there is getting out there and having  a blast learning and making your life better.&lt;/p&gt;

  &lt;p&gt;Seems like an easy choice. Go kick some ass.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
 </entry>
 
 <entry>
   <title>Getting up and running with Amber</title>
   <link href="http://scottpatten.ca/2011/12/getting-up-and-running-with-amber.html"/>
   <updated>2011-12-08T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2011/12/getting-up-and-running-with-amber</id>
   <content type="html">&lt;p&gt;I was quite excited by Yehuda Katz’ &lt;a href=&quot;http://yehudakatz.com/2011/12/08/announcing-amber-js/&quot;&gt;announcement of Amber.js&lt;/a&gt; this morning. I had been intrigued by SproutCore, but hadn’t really liked how big it felt. So, when Yehuda said “If you played with SproutCore and liked the concepts but felt like it was too heavy, give Amber a try”, I listened.&lt;/p&gt;

&lt;p&gt;The following is mostly just notes of what I learned. It’s not at all complete, but it should get you up and running and get you something to play with quickly.&lt;/p&gt;

&lt;h2 id=&quot;getting-it-on-your-machine&quot;&gt;Getting it on your machine&lt;/h2&gt;

&lt;p&gt;Assuming that you have git, Ruby 1.9.2 and a recent version of bundler installed, this is pretty straightforward. So, use &lt;code&gt;rvm use 1.9.2&lt;/code&gt; or the &lt;code&gt;rbenv&lt;/code&gt; equivalent if you need to. These commands should do it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    git clone https://github.com/amberjs/amber.js.git
    cd amber.js
    bundle install
    rake dist
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will create &lt;code&gt;sproutcore.js&lt;/code&gt; and &lt;code&gt;sproutcore.min.js&lt;/code&gt; in the &lt;code&gt;dist&lt;/code&gt; directory.&lt;/p&gt;

&lt;h2 id=&quot;creating-hello-world&quot;&gt;Creating Hello World&lt;/h2&gt;

&lt;p&gt;Now that we’ve got the Javascript files, we can make a new project skeleton for a hello world app. We want to end up with an &lt;code&gt;helloworld.html&lt;/code&gt; file where we put our HTML, and a &lt;code&gt;javascripts&lt;/code&gt; directory where we put some JS files to include.&lt;/p&gt;

&lt;!--more--&gt;

&lt;hr /&gt;

&lt;pre&gt;&lt;code&gt;mkdir hello_world
cd hello_world
mkdir javascripts
touch helloworld.html
cd javascripts
wget http://code.jquery.com/jquery-1.7.1.js
ln -s jquery-1.7.1.js jquery.js
ln -s &amp;lt;path-to-sproutcore.js&amp;gt;
cd ..
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;Okay, we’re all set now.&lt;/p&gt;

&lt;p&gt;The first thing we’re going to do is create a SC application (it’s still called SC right now, presumably this will be renamed to Amber sometime soon) and a &lt;code&gt;Planet&lt;/code&gt; model.  We’ll then instantiate an instance of this model and show it off on the page.&lt;/p&gt;

&lt;p&gt;Edit &lt;code&gt;helloworld.html&lt;/code&gt; to look like this:&lt;/p&gt;

&lt;hr /&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- JavaScript includes --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;javascripts/jquery.js&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;javascripts/sproutcore.js&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;HelloWorld&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Planet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;star&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;currentPlanet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Planet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Earth&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;star&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Sol&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/x-handlebars&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;Hello&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;hr /&gt;

&lt;p&gt;Let’s go through that step-by-step.&lt;/p&gt;

&lt;p&gt;First, we load up &lt;code&gt;jquery.js&lt;/code&gt; and &lt;code&gt;sproutcore.js&lt;/code&gt;. Make sure to load &lt;code&gt;jquery.js&lt;/code&gt; first or things will blow up.&lt;/p&gt;

&lt;p&gt;Next, we set up our SproutCore (again, presumably soon to be Amber) application with&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;HelloWorld&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For now, I’m thinking of this as a name-space for the app.&lt;/p&gt;

&lt;p&gt;Next, we make our &lt;code&gt;Planet&lt;/code&gt; class.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Planet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;star&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This sets up a planet with &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;star&lt;/code&gt; and &lt;code&gt;position&lt;/code&gt; attributes. The values of the hash are the default values.&lt;/p&gt;

&lt;p&gt;Finally, we create an instance of a planet with &lt;code&gt;HelloWorld.Planet.create&lt;/code&gt;, passing in a hash of attributes and assigning it to &lt;code&gt;HelloWorld.currentPlanet&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That’s the end of the script.&lt;/p&gt;

&lt;p&gt;Now comes the crazy part. We put a Handlebars template in the body tag, and it gets processed by Amber and stuck in to the DOM. The part inside the double-curly-braces gets replaced with what you would expect: the name of the planet we created. Also, it is bound to &lt;code&gt;HelloWorld.currentPlanet&lt;/code&gt;, so any time the name of the planet changes, our view will change.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/demos/getting_up_and_running_with_amber/helloworld1.html&quot;&gt;Play around with the demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Try opening up your JavaScript console and changing the name of the planet (hint: &lt;code&gt;HelloWorld.currentPlanet.set(&#39;name&#39;, &#39;Venus&#39;)&lt;/code&gt;).&lt;/p&gt;

&lt;h2 id=&quot;hooking-up-a-form&quot;&gt;Hooking up a form&lt;/h2&gt;

&lt;p&gt;Okay, that’s useful, but we can’t expect our users to open up JavaScript consoles. Let’s hook our model up to a form.&lt;/p&gt;

&lt;p&gt;To do this, we’ll create a view and a template. Notice that we’re taking a short-cut here and skipping the ‘C’ part of the MVC triumvarate. This is not a good idea, of course, but I’m getting tired and I don’t want to make this post too long.&lt;/p&gt;

&lt;p&gt;The view is going to be a simple text field, so we’re going to extend &lt;code&gt;SC.TextField&lt;/code&gt;. Put this at the bottom of your script block in the head of the HTML:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PlanetNameView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TextField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;insertNewline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;value&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;currentPlanet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;value&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And put this below the handlebars template in the body of the HTML:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/x-handlebars&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Rename&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;planet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;a href=&quot;/demos/getting_up_and_running_with_amber/helloworld2.html&quot;&gt;Here’s a demo to play around with&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think that’s it for now. So far, this is looking pretty fun and magical.&lt;/p&gt;

&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;

&lt;p&gt;If you’re intrigued, you can get more information from &lt;a href=&quot;https://github.com/amberjs/amber.js/blob/master/README.md&quot;&gt;the Amber.js README&lt;/a&gt; and the &lt;a href=&quot;http://guides.sproutcore20.com/&quot;&gt;SproutCore 2.0 Guides&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Speeding up Jekyll Generation</title>
   <link href="http://scottpatten.ca/2011/11/speeding-up-jekyll-generation.html"/>
   <updated>2011-11-18T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2011/11/speeding-up-jekyll-generation</id>
   <content type="html">&lt;p&gt;One of the only complaints you’ll see out there about &lt;a href=&quot;https://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt; is that when sites get bigger, it starts to slow down.&lt;/p&gt;

&lt;p&gt;Luckily, this is easy to fix. Unfortunately, it’s apparently not obvious as you still &lt;a href=&quot;http://brandontreb.com/wordpress-to-jekyll-and-back-again/&quot;&gt;see people complaining about it&lt;/a&gt;. Here’s my attempt at proselytizing for Jekyll :).&lt;/p&gt;

&lt;p&gt;If you run &lt;code&gt;jekyll --help&lt;/code&gt;, you’ll see that there’s a &lt;code&gt;--limit_posts&lt;/code&gt; option. If you set this to 1, then you’ll only re-generate your most recent post when you save. This is usually exactly what you want. If you’re working on a slightly older post, then bump it up to 3 or 4.&lt;/p&gt;

&lt;p&gt;Like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; jekyll --limit_posts 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I’ve put this in a rake task&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:jekyll&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;start the jekyll server in auto mode&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:num_posts&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;num_posts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:num_posts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;jekyll --auto --server --pygments&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot; --limit_posts &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_posts&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_posts&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;running &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So I can start Jekyll like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rake jekyll:server[1]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and only see the current post, and it’s blazing fast.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Opening up ports to your security group on EC2</title>
   <link href="http://scottpatten.ca/2011/11/opening-up-ec2-ports-internally.html"/>
   <updated>2011-11-18T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2011/11/opening-up-ec2-ports-internally</id>
   <content type="html">&lt;p&gt;Say you have a cluster of EC2 instances that you want to be able to talk to each other, but you don’t want everyone in the world to be able to join in on the conversation. For example, I was just setting up a typical cluster of servers:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A rails app server&lt;/li&gt;
  &lt;li&gt;A DB server&lt;/li&gt;
  &lt;li&gt;A daemon server&lt;/li&gt;
  &lt;li&gt;A DB slave&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I want all of these servers to be able to talk to each other over port 3306 (the MySQL port), but I don’t want the whole world to be able to connect over port 3306.&lt;/p&gt;

&lt;p&gt;You need two things:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A security group&lt;/li&gt;
  &lt;li&gt;Your EC2 user id.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Assuming you have your ec2 command line tools set up already, here’s how you would do it. This will create a group called &lt;code&gt;yoursecuritygroup&lt;/code&gt; with ports 22 (ssh), 80 (http) and 443 (https) open to the world, but with all other ports only open to other computers in the same security group.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; ec2-create-group --description &quot;yoursecuritygroup production&quot; yoursecuritygroup
$&amp;gt; ec2-authorize yoursecuritygroup -p 22
$&amp;gt; ec2-authorize yoursecuritygroup -p 80
$&amp;gt; ec2-authorize yoursecuritygroup -p 443
$&amp;gt; ec2-authorize yoursecuritygroup -o yoursecuritygroup -u 1234-1234-1234
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You need to add your user id here in place of &lt;code&gt;1234-1234-1234&lt;/code&gt;. You can find this by going to &lt;a href=&quot;https://aws-portal.amazon.com/gp/aws/developer/account?ie=UTF8&amp;amp;action=access-key&quot;&gt;https://aws-portal.amazon.com/gp/aws/developer/account?ie=UTF8&amp;amp;action=access-key&lt;/a&gt; and scrolling to the bottom. You want your AWS Account ID.&lt;/p&gt;

&lt;p&gt;Now when you spin up your instances, make sure to start them in the &lt;code&gt;yoursecuritygroup&lt;/code&gt; group using the &lt;code&gt;--group&lt;/code&gt; argument:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ec2-run-instances --key your-key --group yoursecuritygroup --block-device-mapping /dev/sda1=:100:false --instance-initiated-shutdown-behavior stop --disable-api-termination --instance-type m1.small  ami-a7f539ce
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And you should be all set.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Multiple Google Analytics Tracking Codes on one Page</title>
   <link href="http://scottpatten.ca/2011/11/multiple-google-analytics-codes-on-one-page.html"/>
   <updated>2011-11-11T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2011/11/multiple-google-analytics-codes-on-one-page</id>
   <content type="html">&lt;p&gt;Say I want to make it so that &lt;a href=&quot;http://leanpub.com&quot;&gt;Leanpub&lt;/a&gt; authors can get Google Analytics information about visits to their page while still sending the info to our Leanpub analytics account. This is pretty easy to do, but finding out how took me a bit of googling.&lt;/p&gt;

&lt;p&gt;Your google analytics script for a normal, single tracking code looks something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;_setAccount&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;UA-1234567-1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;_trackPageview&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;script&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;text/javascript&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;https:&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;protocol&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;https://ssl&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;http://www&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;.google-analytics.com/ga.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;script&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;insertBefore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s all fine and dandy, but what if you want to have two codes in there?&lt;/p&gt;

&lt;p&gt;Turns out it’s pretty simple. You add another set of &lt;code&gt;_gaq.push&lt;/code&gt; lines, right after the current ones and before &lt;code&gt;(function() {&lt;/code&gt;. Something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;account2._setAccount&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;UA-1234567-1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;account2._trackPageview&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code&gt;account2&lt;/code&gt; part can be anything you want. In fact, you can stick in a bunch of them if you want, resulting in something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;_setAccount&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;UA-1234567-1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;_trackPageview&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;account2._setAccount&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;UA-1234568-1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;account2._trackPageview&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;account3._setAccount&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;UA-1234569-1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;account3._trackPageview&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;account4._setAccount&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;UA-1234570-1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_gaq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;account4._trackPageview&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;script&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;text/javascript&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;https:&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;protocol&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;https://ssl&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;http://www&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;.google-analytics.com/ga.js&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;script&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;insertBefore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Nice!&lt;/p&gt;

&lt;p&gt;More info can be found here: &lt;a href=&quot;http://code.google.com/apis/analytics/docs/tracking/asyncUsageGuide.html#MultipleCommands&quot;&gt;http://code.google.com/apis/analytics/docs/tracking/asyncUsageGuide.html#MultipleCommands&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>How big is a Googol, anyway?</title>
   <link href="http://scottpatten.ca/2011/05/how-big-is-a-googol.html"/>
   <updated>2011-05-14T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2011/05/how-big-is-a-googol</id>
   <content type="html">&lt;p&gt;A friend of mine told his son that a Googol is a huge number. My kids caught on, so now I hear googol used in conversation all the time.&lt;/p&gt;

&lt;p&gt;You know, like this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I could eat 100 chocolate Easter eggs!&lt;/p&gt;

  &lt;p&gt;&lt;em&gt;I&lt;/em&gt; could eat 1000!&lt;/p&gt;

  &lt;p&gt;Oh Yeah? Well, &lt;em&gt;I&lt;/em&gt; could eat a googol!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Googol&quot;&gt;A googol&lt;/a&gt; is 10&lt;sup&gt;100&lt;/sup&gt;. That’s 1, followed by 100 zeroes. It’s a ridiculously big number. It’s a number purely designed to awe the imagination. It’s not really useful in real life.&lt;/p&gt;

&lt;p&gt;After hearing googol-bombs dropped all the time like this, you sort of get inured to it. A couple of days ago, though, I started thinking about how big a googol really was. My friend (the same one who brought googol in to my life) and I tried to think of something where googol was a reasonable scale, and came up blank.&lt;/p&gt;

&lt;p&gt;Huh.&lt;/p&gt;

&lt;p&gt;So, the question I want to ask is: is there anything that has a googol of it in the universe?&lt;/p&gt;

&lt;p&gt;Let’s start with some standard “big quantity” things.&lt;/p&gt;

&lt;h2 id=&quot;the-number-of-grains-of-sand-on-the-earth&quot;&gt;The number of grains of sand on the earth.&lt;/h2&gt;

&lt;p&gt;I don’t really care about accuracy here. So, &lt;a href=&quot;http://wiki.answers.com/Q/How_many_grains_of_sand_are_there_in_the_world&quot;&gt;I’ll just google it&lt;/a&gt;. The first answer says&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;There are seven quintillion five quadrillion grains of sand on all the beaches of the world. That’s a 75 with 17 zeros following!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, in scientific notation that’s 7.5 x 10&lt;sup&gt;18&lt;/sup&gt;. It’s a big number, but we’re nowhere near close.&lt;/p&gt;

&lt;h2 id=&quot;how-many-stars-are-there&quot;&gt;How many stars are there?&lt;/h2&gt;

&lt;p&gt;Okay, let’s up the ante a bit. Another quick google search yields &lt;a href=&quot;http://www.esa.int/esaSC/SEM75BS1VED_index_0.html&quot;&gt;this answer&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;With this simple calculation you get something like 10&lt;sup&gt;22&lt;/sup&gt; to 10&lt;sup&gt;24&lt;/sup&gt; stars in the Universe. This is only a rough number, as obviously not all galaxies are the same, just like on a beach the depth of sand will not be the same in different places.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Obviously, these numbers are nowhere near big enough. Surely the number of atoms is going to be bigger.&lt;/p&gt;

&lt;h2 id=&quot;how-many-atoms-are-in-the-universe&quot;&gt;How many atoms are in the universe?&lt;/h2&gt;

&lt;p&gt;From &lt;a href=&quot;http://en.wikipedia.org/wiki/Observable_universe&quot;&gt;the Wikipedia article on the Observable Universe&lt;/a&gt; (which is a wealth of numbers for making these kinds of calculations):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;two approximate calculations give the number of atoms in the observable universe to be close to 10&lt;sup&gt;80&lt;/sup&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We’re getting closer!&lt;/p&gt;

&lt;p&gt;Well, it may feel like it, but we’re still ridiculously far off. We’re off by a factor of 10&lt;sup&gt;20&lt;/sup&gt;. That’s part of the mind-bend of playing around with googol. The biggest number we’ve come up so far with is 10&lt;sup&gt;80&lt;/sup&gt;. That means we’d need 10&lt;sup&gt;20&lt;/sup&gt; universes just like ours to have a googol of atoms. Yikes!&lt;/p&gt;

&lt;h2 id=&quot;how-many-particles-are-in-the-universe&quot;&gt;How many particles are in the universe?&lt;/h2&gt;

&lt;p&gt;So, if we ask how many &lt;em&gt;particles&lt;/em&gt; are in the universe, the number of fermions (things that make up matter, like protons and neutrons and electrons) isn’t going to get much larger than the number of atoms. Most of the universe is made of hydrogen, which has one proton and one electon. Even if we pretended that the atoms in the universe were made of some heavy element (say, Uranium), and then break the protons and neutrons up into their component quarks, we’d only add two or three orders of magniture to the number.&lt;/p&gt;

&lt;p&gt;Okay, so what about photons and neutrinos and stuff like that? Well, I found something &lt;a href=&quot;http://www.cs.umass.edu/~immerman/stanford/universe.html&quot;&gt;here&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Of course, besides material particles there are also lots of photons and neutrinos flying around the Universe. It is estimated that there are about 1e9 times as many photons and neutrinos as atoms in the Universe.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, that gives us ~ 10&lt;sup&gt;89&lt;/sup&gt;. Closer, but still off by a factor of 10&lt;sup&gt;11&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;It looks to me like our initial goal of finding something tangible that had more than a googol of it has failed.&lt;/p&gt;

&lt;p&gt;Just for fun, let’s make one more calculation.&lt;/p&gt;

&lt;h2 id=&quot;packing-the-universe-with-sand&quot;&gt;Packing the universe with sand&lt;/h2&gt;

&lt;p&gt;Okay, let’s go crazy here. Remember the grains of sand in the earth question we started with? Let’s pretend we pack the &lt;em&gt;whole universe&lt;/em&gt; with grains of sand. Yeah, the whole thing. Ignore questions of gravitational collapse and turning the whole universe into a giant black hole of what used to be sand and all that.&lt;/p&gt;

&lt;p&gt;So, from that same  Wikipedia page on the &lt;a href=&quot;http://en.wikipedia.org/wiki/Observable_universe&quot;&gt;observable universe&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The observable universe is thus a sphere with a diameter of about 28 billion parsecs (93 billion, or 9.3 × 10&lt;sup&gt;10&lt;/sup&gt;, light years). Assuming that space is roughly flat, this size corresponds to a comoving volume of about 3 × 10&lt;sup&gt;80&lt;/sup&gt; cubic meters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cool! So that means, based on our number of atoms in the universe number above, there’s 1 atom for every three cubic meters in the observable universe. That’s not enough! Let’s see what happens if we pack the whole thing with sand.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.6footsix.com/my_weblog/how-many-grains-of-sand-i.html&quot;&gt;This page here&lt;/a&gt; gives a reasonable estimate for the size of a grain of sand. The number they come up with is 8 per cubic millimeter. Let’s make life easier and round that up to 10. That means we’ll get 10 grains/mm&lt;sup&gt;3&lt;/sup&gt; X 10&lt;sup&gt;9&lt;/sup&gt; mm&lt;sup&gt;3&lt;/sup&gt;/m&lt;sup&gt;3&lt;/sup&gt; = 10&lt;sup&gt;10&lt;/sup&gt; grains/m&lt;sup&gt;3&lt;/sup&gt;. Multiplying that by the volume of the universe (and if you’re feeling bored, think about how crazy that phrase is…) gives us 10&lt;sup&gt;90&lt;/sup&gt; grains of sand.&lt;/p&gt;

&lt;p&gt;That’s right, if we fill the entire universe with grains of sand we’d still need 10&lt;sup&gt;10&lt;/sup&gt; universes to get a googol grains of sand.&lt;/p&gt;

&lt;p&gt;Hmph. Okay, but how many atoms would that be?&lt;/p&gt;

&lt;p&gt;To make things easier, let’s just make the universe one giant silicon crystal. Silicon has a density of 2.3 g/cm&lt;sup&gt;3&lt;/sup&gt; (&lt;a href=&quot;http://en.wikipedia.org/wiki/Silicon&quot;&gt;again, Wikipedia is our friend&lt;/a&gt;), or 2.3 x 10&lt;sup&gt;6&lt;/sup&gt; g/m&lt;sup&gt;3&lt;/sup&gt;. Silicon has an atomic mass of 28 g/mol (the stable isotope of Silicon has 14 protons and 14 neutrons).&lt;/p&gt;

&lt;p&gt;So, a cubic meter of silicon has&lt;/p&gt;

&lt;pre&gt;
 2.3 x 10&lt;sup&gt;6&lt;/sup&gt; g/m&lt;sup&gt;3&lt;/sup&gt; / 28 g/mol X 6.022 10&lt;sup&gt;23&lt;/sup&gt; atoms/mol

 =

 4.95 X 10&lt;sup&gt;28&lt;/sup&gt; atoms/m&lt;sup&gt;3&lt;/sup&gt;

&lt;/pre&gt;

&lt;p&gt;Ooo, we may be on to something here.&lt;/p&gt;

&lt;p&gt;Multiply that by the volume of the universe:&lt;/p&gt;

&lt;pre&gt;
 4.95 X 10&lt;sup&gt;28&lt;/sup&gt; atoms/m&lt;sup&gt;3&lt;/sup&gt; X 3 × 10&lt;sup&gt;80&lt;/sup&gt; m&lt;sup&gt;3&lt;/sup&gt; = 1.48 X 10&lt;sup&gt;109&lt;/sup&gt; atoms

= 1.48 X 10&lt;sup&gt;9&lt;/sup&gt; googol atoms!
&lt;/pre&gt;

&lt;p&gt;We did it!&lt;/p&gt;

&lt;p&gt;We had to make a ridiculous assumption that could never happen, but in the end managed to get a number that was bigger than a googol.&lt;/p&gt;

&lt;p&gt;Phew.&lt;/p&gt;

&lt;h2 id=&quot;what-did-i-miss&quot;&gt;What did I miss?&lt;/h2&gt;

&lt;p&gt;Thanks for reading this far.&lt;/p&gt;

&lt;p&gt;If you’re interested, &lt;a href=&quot;http://news.ycombinator.com/item?id=2548339&quot;&gt;upvote it on hacker news&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What did you think? Is there any reasonable number of real-live countable things in our current universe that has more than a googol? Perhaps if we include gravitons, or dark matter, or something like that?&lt;/p&gt;

&lt;p&gt;Also, this post was written in about an hour in a coffee shop, so I’m sure I’ve made errors. Let me know if you find any!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Booting an Alestic EC2 Image with a Larger Root Disk</title>
   <link href="http://scottpatten.ca/2011/05/booting-an-alestic-ec2-image-with-larger-root-disk.html"/>
   <updated>2011-05-06T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2011/05/booting-an-alestic-ec2-image-with-larger-root-disk</id>
   <content type="html">&lt;p&gt;I always start up my new EC2 images using &lt;a href=&quot;http://alestic.com/&quot;&gt;Alestic’s awesome Ubuntu images&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I typically pick the EBS boot images. My only complaint has been that the EBS size is too small. They’re only 8 GB by default.&lt;/p&gt;

&lt;p&gt;In the past, the fix has been to follow &lt;a href=&quot;http://alestic.com/2010/02/ec2-resize-running-ebs-root&quot;&gt;these directions&lt;/a&gt;: start up a server, terminate it, detach the volume, make a snapshot of it, create a new AMI from the snapshot and then start up a new server with that AMI.&lt;/p&gt;

&lt;p&gt;Too much work for me.&lt;/p&gt;

&lt;p&gt;Today I was starting up another server, and I did a bit of googling and found out that with the latest images, you can just pass in a parameter to your ec2-run-instances command and set the boot disk size to anything you want. Woo hoo!&lt;/p&gt;

&lt;p&gt;Here’s the &lt;a href=&quot;http://groups.google.com/group/ec2ubuntu/browse_thread/thread/cb0c209635d248f0/be23fff5d14b085d?pli=1&quot;&gt;google groups thread&lt;/a&gt;. Look for the message from Scott Moser.&lt;/p&gt;

&lt;p&gt;Here’s the command I used to create a new instance with a 100GB boot disk:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ec2-run-instances --key your-ec2-key \
 --block-device-mapping /dev/sda1=:100:false \
 --instance-initiated-shutdown-behavior stop \
 --disable-api-termination --instance-type m1.small  ami-06ad526f
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The magic part is the &lt;code&gt;--block-device-mapping /dev/sda1=:100:false&lt;/code&gt;. This takes three params. The first (which is blank here) allows you to pick a volume to mount as the root. If it’s blank, then a new EBS volume will be created.&lt;/p&gt;

&lt;p&gt;The second (&lt;code&gt;100&lt;/code&gt;) is the size of the boot disk. Change the 100 there to be whatever you want the size of the boot disk to be, in GB.&lt;/p&gt;

&lt;p&gt;The third is whether or not to destroy the volume when you kill the instance, and can be either &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;. Unless this is a throwaway instance, you’re going to want this to be &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>SLL Subscribers Vs Time</title>
   <link href="http://scottpatten.ca/2010/09/sll-subscribers-vs-time.html"/>
   <updated>2010-09-10T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2010/09/sll-subscribers-vs-time</id>
   <content type="html">&lt;p&gt;First, if you’re not a fan of Eric Ries’ &lt;a href=&quot;http://startuplessonslearned.com&quot;&gt;Startup Lessons Learned&lt;/a&gt;, this post won’t be very fun for you. Luckily, there’s a very simple remedy for that: go there right now and read a few articles! There’s some amazing stuff, and I guarantee that you’ll learn something new and thought provoking.&lt;/p&gt;

&lt;p&gt;If you’re intrigued and want to read all of the posts, then I also humbly recommend you go and buy his blog converted to a PDF on Leanpub: &lt;a href=&quot;http://leanpub.com/startuplessonslearned&quot;&gt;http://leanpub.com/startuplessonslearned&lt;/a&gt;.  It’s much easier to read it as a PDF than clicking through all of the blog posts, and you get updates every month or so with all of the new posts.&lt;/p&gt;

&lt;p&gt;Okay, now that that’s out of the way, let’s get down to the data!&lt;/p&gt;

&lt;p&gt;Every once in a while, Eric asks his subscribers to do a survey for him so he can find out about them.  The title of the survey is always something like “Lo, my 50 subscribers, who are you”.  The latest one is &lt;a href=&quot;http://www.startuplessonslearned.com/2010/09/lo-my-57692-subscribers-who-are-you.html&quot;&gt;Lo, my 57692 subscribers, who are you?&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Just for fun, I decided to plot the number of subscribers Vs time.  Here are the results:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/sll_subscribers_vs_time.png&quot; alt=&quot;Number of SLL subscribers Vs Time&quot; /&gt;.&lt;/p&gt;

&lt;p&gt;Hockey stick graph?  I think so!&lt;/p&gt;

&lt;p&gt;That naturally leads to the question: can Eric legitimately say that he has exponential growth? Let’s take a look…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/sll_subscribers_with_fit.png&quot; alt=&quot;Number of SLL subscribers Vs Time with curve fits&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sorry, Eric, but the data does not support that conclusion.  You &lt;em&gt;can&lt;/em&gt; say that you have second order polynomial growth.&lt;/p&gt;

&lt;p&gt;I know, not quite as sexy, but I guess it’ll just have to do.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The Myth of the Zone</title>
   <link href="http://scottpatten.ca/2010/08/the-myth-of-the-zone.html"/>
   <updated>2010-08-28T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2010/08/the-myth-of-the-zone</id>
   <content type="html">&lt;p&gt;I’ve been thinking about how I work best for a while, and I was inspired by &lt;a href=&quot;http://www.peterarmstrong.com/?p=336&quot;&gt;Peter’s post&lt;/a&gt; on his new workflow/schedule to write something up about it.&lt;/p&gt;

&lt;p&gt;First, the provocative title is only partly link-bait.  For me, the zone really is a myth.  I keep hearing and reading about coders getting into zones and coming out of the mist 10 hours later with reams of awesome code (and, presumably, a really full bladder).&lt;/p&gt;

&lt;p&gt;I’ve never had this happen.&lt;/p&gt;

&lt;p&gt;Maybe it’s just me, and everyone else does get into a zone regularly.  Maybe the zone isn’t as universal as hacker literature makes it out to be.  Maybe the zone is a young hacker thing, and I’m getting towards the old side of the scale. Or, maybe it really is a myth.&lt;/p&gt;

&lt;p&gt;Whatever the answer is, my version of “The Zone” looks like this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Start working on something.&lt;/li&gt;
  &lt;li&gt;Hit a wall where I can’t find a solution or the solution I’ve come up with is too complicated.&lt;/li&gt;
  &lt;li&gt;Realize “Hey, I’ve hit a wall.  I should change the scenery” (The realization is the hard part).&lt;/li&gt;
  &lt;li&gt;Go for a walk / go to a coffee shop / leave my home office and head to the “real” office / etc.&lt;/li&gt;
  &lt;li&gt;On the way there, mull over the problem.  Or don’t bother, and let my subconscious do that for me.&lt;/li&gt;
  &lt;li&gt;Arrive at my destination, unpack my laptop, and find out that I’ve solved the problem or, at the very least, have come up with a new way to look at solving the problem.&lt;/li&gt;
  &lt;li&gt;Happily code away until I get stuck again, whereupon I go for another walk.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Luckily, I live close to a lot of coffee shops.  Also, our new office is about a 25 minute walk from home, and a lot of those coffee shops are en route.&lt;/p&gt;

&lt;p&gt;This means that I can start working at home (or, preferably, at a coffee shop.  That way I don’t spend half an hour surfing the web in the morning).  Then, when I hit that inevitable wall, I continue my commute and arrive at the office with a fresh solution to whatever problem I’ve been working on.&lt;/p&gt;

&lt;p&gt;Here are a few more thought on this in no particular order.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The hard part really is coming to the realization that I’m banging my head against the wall.  I’ve started listening more closely to those little voices in the back of my head saying “There must be an easier way to do this” or “Do you really need this feature?” or “Sheesh, I need a break.” Once I started doing this, I spent a lot less time going down rat holes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Part of the problem is that I tend to dive into the details really quickly and don’t spend long enough looking at the big picture.  I’m working on this.  I’d suspect that most (not all, but most) programmers do this too.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It’s a heckuva lot more productive to go for a 10 minute walk than to bang your head against a wall for an hour.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;This would be tough to do in a typical office environment – I don’t think I would’ve been able to go out for a walk and a coffee a few times a day while I was working at Creo (and Creo was far from being a bureaucratic, top-down organization).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pair programming or describing the problem to someone or &lt;a href=&quot;http://en.wikipedia.org/wiki/Rubber_duck_debugging&quot;&gt;Rubber Ducking&lt;/a&gt; also get you out of those ruts.  You don’t get those nice walks, though.  Also, you may break someone out of their zone if you interrupt them to describe the problem to them…&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Surfing the web does not give you the same results as going for a walk.  You absolutely have to do something active.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://37signals.com/svn/posts/1001-standing-versus-sitting&quot;&gt;Jamis Buck recommends&lt;/a&gt; getting a standing desk to help you walk away from the desk more easily.  I may have to try this.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’d love to hear any thoughts you have on the zone, whether or not it’s a myth, and how you stop yourself from banging your head against the wall.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Custom Validators with Validatious</title>
   <link href="http://scottpatten.ca/2010/08/custom-validators-with-validatious.html"/>
   <updated>2010-08-10T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2010/08/custom-validators-with-validatious</id>
   <content type="html">&lt;p&gt;When I &lt;a href=&quot;/2010/08/using-validatious.html&quot;&gt;talked about Validatious&lt;/a&gt; previously, I had written almost no Javascript and had no need for any validations besides making sure that fields were required and of a certain minimum length.&lt;/p&gt;

&lt;p&gt;On another project, I needed to validate some North American phone numbers and Canadian postal codes.  It turned out to be really simple to add custom validations.  Here’s how it’s done.&lt;/p&gt;

&lt;p&gt;First, here’s a form:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;test_form&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;validate&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;formset&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;address&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Address&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;address&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;address&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;required&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;formset&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;postal_code&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Postal Code&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;postal_code&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;postal_code&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;required cndpostalcode&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;formset&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;phone_number&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Phone Number&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;phone_number&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;phone_number&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;required phone&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that I’ve added a class of &lt;code&gt;cdnpostalcode&lt;/code&gt; to the postal code input and a class of &lt;code&gt;phone&lt;/code&gt; to the phone number input.  You still need the &lt;code&gt;required&lt;/code&gt; class to turn on the validation.&lt;/p&gt;

&lt;p&gt;This won’t do anything other than require that the inputs be filled out yet, as we haven’t added our custom validators in.  To register a validator, you do something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Validator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;validatorClassName&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* some call back that returns true or false */&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Most of the time, the callback is a regular expression.  Let’s tackle the Canadian Postal Code one first, as they’re a bit simpler.&lt;/p&gt;

&lt;p&gt;A Canadian Postal Code looks like A1A 1A1 or S7J 3A2 or H0H 0H0 ( bet you didn’t know that Santa lived in Canada! ).  It’s letter-number-letter space number-letter-number.  The space is optional, too.  So, a regular expression to match a Canadian Postal Code might look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/^\w\d\w\s*\d\w\s$/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We’ll register the class &lt;code&gt;cdnpostalcode&lt;/code&gt; to trigger this validation like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Validator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;cdnpostalcode&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^\w\d\w\s*\d\w\d$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The phone number validator is exactly the same, except the regular expression is a bit more hairy.  This regex is from &lt;a href=&quot;http://regexlib.com/Search.aspx?k=phone+number&amp;amp;c=7&amp;amp;m=5&amp;amp;ps=20&quot;&gt;regexlib.com&lt;/a&gt; (I added in the part that accepts an extension).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Validator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;phone&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})[ x0-9]*$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we add those two chunks of Javascript to the HTML that calls our form, then they will validate the postal code and phone number correctly.  The only problem is that the validation error message will be something like “Postal Code does not pass cdnpostalcode validator”.  Not very pretty.  There are a few more options to &lt;code&gt;Validator.reg&lt;/code&gt; that will allow us to fix that.&lt;/p&gt;

&lt;p&gt;The signature for &lt;code&gt;Validator.reg&lt;/code&gt; looks like this (it’s in &lt;code&gt;src/core/validator.js&lt;/code&gt;):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aliases&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;acceptEmpty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So far, we’ve only used the first two parameters (&lt;code&gt;name&lt;/code&gt; and &lt;code&gt;fn&lt;/code&gt;).  The &lt;code&gt;params&lt;/code&gt; argument would allow us to specify the parameters used in the validator.  We don’t need that, so we’ll pass in &lt;code&gt;null&lt;/code&gt;.  Then, we can set the default message.  Like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;postal_code_message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;You must provide a valid Canadian Postal Code&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Validator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;cdnpostalcode&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^\w\d\w\s*\d\w\d$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;postal_code_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;similarly for the phone validator:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;phone_message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;You must provide a valid phone number&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Validator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;phone&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})[ x0-9]*$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;phone_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here’s what the full HTML looks like.  You can &lt;a href=&quot;/demos/validatious_with_custom_validations.html&quot;&gt;see this form in action here&lt;/a&gt;.  If you’re intrigued, make sure to go &lt;a href=&quot;http://validatious.org&quot;&gt;check out Validatious&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Demo: Custom Validations with Validatious&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;style&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;messages&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;list-style-type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;px&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;messages&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Demo: Custom Validations with Validatious&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;test_form&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;validate&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;formset&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;address&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Address&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;address&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;address&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;required&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;formset&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;postal_code&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Postal Code&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;postal_code&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;postal_code&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;required cdnpostalcode&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;formset&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;phone_number&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Phone Number&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;phone_number&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;phone_number&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;required phone&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/2010/08/custom-validators-with-validatious.html&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Back to the blog post&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/demos/javascripts/validatious.min.js&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// make the validations happen instantly&lt;/span&gt;

      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;postal_code_message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;You must provide a valid Canadian Postal Code&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Validator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;cdnpostalcode&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^\w\d\w\s*\d\w\d$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;postal_code_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;phone_message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;You must provide a valid phone number&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Validator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;phone&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})[ x0-9]*$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;phone_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</content>
 </entry>
 
 <entry>
   <title>Validating with Validatious: A Quick Tutorial</title>
   <link href="http://scottpatten.ca/2010/08/using-validatious.html"/>
   <updated>2010-08-03T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2010/08/using-validatious</id>
   <content type="html">&lt;p&gt;I had a need for some client side validation for a project, so I looked into a few validation plugins.  We’re using JQuery on the project (of course!), so I looked into the standard jquery validation plugins (&lt;a href=&quot;http://plugins.jquery.com/project/jqueryvalidate&quot;&gt;jquery.validate&lt;/a&gt; looked nice, and so did &lt;a href=&quot;http://plugins.jquery.com/project/validate&quot;&gt;jQuery Validation&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;In the end, though, I ended up going with the totally unobtrusive &lt;a href=&quot;http://validatious.org/&quot;&gt;Validatious&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’m totally happy with my choice, but I ran into a gotchas and figured out a few things that I thought I should mention.&lt;/p&gt;

&lt;p&gt;First, though, a quick overview of Validatious.&lt;/p&gt;

&lt;h2 id=&quot;a-quick-intro-to-validatious&quot;&gt;A quick intro to Validatious&lt;/h2&gt;

&lt;p&gt;Validatious has two different APIs: a &lt;a href=&quot;http://validatious.org/learn/features/dsl&quot;&gt;Javascript DSL&lt;/a&gt; and an &lt;a href=&quot;http://validatious.org/learn/features/html&quot;&gt;HTML extension&lt;/a&gt;.  I used the HTML extension.&lt;/p&gt;

&lt;p&gt;To use it, you load the script with a standard script tag&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/javascripts/validatious.min.js&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then, you add some class names to elements.  For example, to validate a form that looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;donation_form&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;/donate&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;First Name&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Last Name&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Amount to donate&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You need to add a class of &lt;code&gt;validate&lt;/code&gt; to the form element, and a validation class to each of the form elements that you want to validate.  Validation classes are things like &lt;code&gt;required&lt;/code&gt; (this element is required) or &lt;code&gt;min-val_3&lt;/code&gt; (this element has a minimum value of 3). Your final file might look something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Validatious Demo&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Validatious Demo&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;donation_form&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;#&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;validate&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;First Name&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;required&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Last Name&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;required&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Amount to donate&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;required min-val_3&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;The donation amount must be at least $3&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;submit&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;submit!&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/demos/javascripts/validatious.min.js&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;All I’ve done is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;include the javascript.&lt;/li&gt;
  &lt;li&gt;add a class of &lt;code&gt;validate&lt;/code&gt; to the form element.&lt;/li&gt;
  &lt;li&gt;add a class of &lt;code&gt;required&lt;/code&gt; to the inputs.&lt;/li&gt;
  &lt;li&gt;add a class of &lt;code&gt;min-val_3&lt;/code&gt; to the final input (I want a donation of at least $3 or it’s not worth my time!).&lt;/li&gt;
  &lt;li&gt;add a title to the donation input to set a custom validation error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice what I didn’t do: write any Javascript.  I like that :).&lt;/p&gt;

&lt;p&gt;You can &lt;a href=&quot;/demos/validatious_form.html&quot;&gt;see the form in action&lt;/a&gt;.  Note that you have to click on submit to see the validation.  Also note that the form and the validation errors are really ugly
.  We’ll fix all of that before the end of this.&lt;/p&gt;

&lt;p&gt;There’s lots more you can do here.  A reasonable place to start learning is on the &lt;a href=&quot;http://validatious.org/learn/features&quot;&gt;Validatious features page&lt;/a&gt;, which contains a bunch of mini tutorials to get you started.&lt;/p&gt;

&lt;h2 id=&quot;the-gotcha&quot;&gt;The Gotcha&lt;/h2&gt;

&lt;p&gt;I mentioned a gotcha.  The problem, which almost made me give up on this plugin right away, is that&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;if you try to validate a form element with no name or id, it blows up with a cryptic error message&lt;/strong&gt; like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;     Uncaught Error: SYNTAX_ERR: DOM Exception 12
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you see this, go through and make sure that all of your form elements have ids and names.&lt;/p&gt;

&lt;p&gt;Go &lt;a href=&quot;/demos/validatious_form_broken.html&quot;&gt;see it in in-action&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;validating-on-blur&quot;&gt;Validating on blur&lt;/h2&gt;

&lt;p&gt;In the original demo, you had to click the submit button to see the validations.  There’s been &lt;a href=&quot;http://www.alistapart.com/articles/inline-validation-in-web-forms/&quot;&gt;some research done&lt;/a&gt; that shows that validating on blur (just after the user has entered the value into the input box) is more effective.  Luckily, that’s easy enough to do.  Just add a script like this to your form:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// make the validations happen instantly&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;putting-validations-closer-to-the-input-field&quot;&gt;Putting validations closer to the input field&lt;/h2&gt;

&lt;p&gt;One thing I didn’t like was that the validation errors were all getting piled up on the top of the form.  It turns out that Validatious inserts the errors at the beginning of the parent of the input element that has an error.  So, the fix is to wrap all of your input elements in a &lt;code&gt;div&lt;/code&gt; tag.  Not perfect, I know, but it’s reasonable if you give it a class name like &lt;code&gt;formset&lt;/code&gt; and use it to hook some CSS in as well.&lt;/p&gt;

&lt;p&gt;That’s semantic, right?  It works, and that’s semantic enough for me.  Don’t tell the standardistas.&lt;/p&gt;

&lt;p&gt;Here’s what that looks like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;donation_form&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;#&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;validate&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;First Name&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;required&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Last Name&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;required&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Amount to donate&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;required min-val_3&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;submit&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;submit!&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;validating-via-javascript&quot;&gt;Validating via Javascript&lt;/h2&gt;

&lt;p&gt;As per usual, I wanted to do something a little different with my form.  It was a very complex form, and I needed to do a few things before submitting.  So, I needed to intercept the click on the submit button.  Also, I wanted to &lt;a href=&quot;http://inspectelement.com/tutorials/create-a-button-with-hover-and-active-states-using-css-sprites/&quot;&gt;style the button as an image with hover and active states&lt;/a&gt;, which is easier to do with an anchor tag than an submit input.&lt;/p&gt;

&lt;p&gt;This all meant that I needed to trigger the validations from Javascript.  You do this with a Javascript line like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;validate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;form_id&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;replacing &lt;code&gt;form_id&lt;/code&gt; with the id of the form you are validating.  The &lt;code&gt;validate&lt;/code&gt; variable will be true if the form is valid, false otherwise.&lt;/p&gt;

&lt;p&gt;In the end, that’s all of the JavaScript I had to use.  Everything else was as simple as adding a class to the form and then to all of the form elements I wanted to validate.  I’m definitely using Validatious next time I need some client side validation.&lt;/p&gt;

&lt;h2 id=&quot;bringing-it-home&quot;&gt;Bringing it home&lt;/h2&gt;

&lt;p&gt;Here’s a final version of the form, with the formset divs, validation on blur, validating via Javascript and even a bit of styling:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Validatious Demo&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;style&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;messages&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;list-style-type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;px&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;messages&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Validatious Demo&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;donation_form&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;#&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;validate&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;First Name&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;first_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;required&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Last Name&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;last_name&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;required&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Amount to donate&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;text&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;amount&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;min-val_3&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;br&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;#&amp;#39;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;submitter&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;submit!&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/demos/javascripts/validatious.min.js&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/demos/javascripts/jquery.js&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// make the validations happen instantly&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;#submitter&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;validate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;donation_form&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// if validate is true then submit via AJAX or something ...&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can &lt;a href=&quot;/demos/validatious_form_all_singing_all_dancing.html&quot;&gt;see it in action here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re interested, go &lt;a href=&quot;http://validatious.org/&quot;&gt;check Validatious out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Update: I’ve also written a post on &lt;a href=&quot;/2010/08/custom-validators-with-validatious.html&quot;&gt;writing custom validators with Validatious&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>My Git Aliases</title>
   <link href="http://scottpatten.ca/2010/07/my-git-aliases.html"/>
   <updated>2010-07-27T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2010/07/my-git-aliases</id>
   <content type="html">&lt;p&gt;After you’ve been using Git for a while, you start to get kind of bored with typing &lt;code&gt;git commit -a -m &quot;some message&quot;&lt;/code&gt; all the time, and you never want to see this message ever again:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $&amp;gt; git stastus
  git: &#39;stastus&#39; is not a git-command. See &#39;git --help&#39;.
  
  Did you mean this?
        status
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(why can’t you just do it for me!)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://kenpratt.net&quot;&gt;Ken&lt;/a&gt; had set up some nice aliases for git on his machine, so I totally stole them. My only regret is that it took me so long to do it. (I am glad that I didn’t do this &lt;em&gt;right&lt;/em&gt; when I started using Git, though – it was worth while getting the long commands deeply ingrained into my memory before I started taking short cuts).&lt;/p&gt;

&lt;p&gt;Here’s what I came up with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   alias gpom=&#39;git push origin master&#39;
   alias st=&#39;git status&#39;
   alias gppp=&#39;git pull peter master&#39;
   alias gcam=&#39;git commit -a -m &#39;
   alias gd=&#39;git diff &#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Obviously you don’t want the &lt;code&gt;git pull peter master&lt;/code&gt; one, but the rest are probably close to something you use all the time.&lt;/p&gt;

&lt;p&gt;I also wanted one that replaces&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  git commit some_file some_other_file -m &quot;commit message&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;with something like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; gcom some_file some_other_file &quot;commit message&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;but my bash-fu wasn’t strong enough, so I resorted to a quick Ruby script instead:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;USAGE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;gcom &amp;lt;file 1&amp;gt; &amp;lt;file 2&amp;gt; &amp;quot;commit message&amp;quot; ==&amp;gt; git commit &amp;lt;file 1&amp;gt; &amp;lt;file 2&amp;gt; -m &amp;quot;commit message&amp;quot;&amp;#39;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;USAGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pop&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;git commit &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; -m &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;These are still a work in progress, and there’s nothing earth shattering here, but I thought I’d throw up a post just for the heck of it.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>How scottpatten.ca came to be</title>
   <link href="http://scottpatten.ca/2010/07/how-scottpattenca-came-to-be.html"/>
   <updated>2010-07-27T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2010/07/how-scottpattenca-came-to-be</id>
   <content type="html">&lt;p&gt;I was happily working away on Leanpub one day when I got a phone call.  It was some guy from the city of Vancouver asking why I hadn’t paid for my business license for spatten design.&lt;/p&gt;

&lt;p&gt;I explained that I was no longer running spatten design as a business, so there was obviously no need to pay the $200 per year fee.  Seemed pretty straight forward to me.&lt;/p&gt;

&lt;p&gt;Unfortunately, he wasn’t buying any of that.  He had gone all CSI on me and done a Google search for spatten design and found a (gasp!) running web site at http://spattendesign.com.  There was a website running called spattendesign.com, therefore I was still in business.&lt;/p&gt;

&lt;p&gt;Q E fucking D.&lt;/p&gt;

&lt;p&gt;He was quite proud of his cyber sleuthing skills, and didn’t want to hear that the fact that the website was running had no bearing on whether or not I was running it as a business.&lt;/p&gt;

&lt;p&gt;The front page of the site looked like this at the time:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/spattendesign-2010-05-03.png&quot; alt=&quot;spattendesign.com on May 3rd, 2010&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note a few things:
1. It says I work full time at Ruboss
2. The latest blog post was on April 20th.  That’s April 20th, 2009.
3. There’s no mention that I do any consulting work as spatten design (and I don’t!  Trust me, running a startup and a consultancy is enough work for me.)&lt;/p&gt;

&lt;p&gt;I tried to explain that there were useful things on that site that people still used (mostly the &lt;a href=&quot;/projects/synching-your-amazon-s3-asset-host-using-capistrano.html&quot;&gt;S3 synch plugin&lt;/a&gt;), but he didn’t really care.  The only thing I could do to avoid paying $200/year for a business license for a business that does not exist was take down the web site.&lt;/p&gt;

&lt;p&gt;After a long and rather unfruitful discussion, I basically hung up on him.&lt;/p&gt;

&lt;p&gt;So, here we are.  I’ve made spattendesign.com redirect to scottpatten.ca.  Hopefully that’s close enough to taking down the site that I don’t get another call from the Googler extraordinaire from the City of Vancouver.&lt;/p&gt;

&lt;p&gt;On the plus side, I finally registered scottpatten.ca, and I had a great time getting this site up and running with &lt;a href=&quot;http://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt;, and got rid of the old blog, which had been running on an old and creaky install of Mephisto.  Also, Jekyll makes me actually want to blog (&lt;a href=&quot;http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html&quot;&gt;like a hacker&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Don’t worry, this is as close as I get to ranting.  Your very irregularly scheduled technical posts will be coming back soon.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The S3 Cookbook</title>
   <link href="http://scottpatten.ca/2009/04/the-s3-cookbook.html"/>
   <updated>2009-04-20T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2009/04/the-s3-cookbook</id>
   <content type="html">&lt;p&gt;One of the many things I&amp;#8217;ve been doing while ignoring this blog has been writing a book.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s called The S3 Cookbook, and I&amp;#8217;m more than happy to announce that it&amp;#8217;s available for sale on Sopobo at &lt;a href=&quot;http://leanpub.com/thes3cookbook&quot;&gt;http://leanpub.com/thes3cookbook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s a bit about the book:&lt;/p&gt;
&lt;p&gt;Amazon&amp;#8217;s Simple Storage Service (S3) has been described as &amp;#8220;Storage in the cloud&amp;#8221;.  I like to think of it as Amazon lending you some hard-drive space on their servers, and giving you lots of interesting ways to put data there and share it with others.&lt;/p&gt;
&lt;p&gt;Getting started with S3 is pretty straightforward, but even with its simple interface (really, because of its simplicity), there are a &lt;strong&gt;lot&lt;/strong&gt; of things you can do with it.  The S3 Cookbook will give you a quick introduction to S3&amp;#8217;s architecture, get you set up with some tools, and then let you explore.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://leanpub.com/thes3cookbook/toc&quot;&gt;The recipes&lt;/a&gt; provide you with the code to do all of the everyday things that people are doing with S3, as well as the more esoteric ones.  They will help you get the simple things done quickly, and inspire you with ideas of your own.&lt;/p&gt;
&lt;p&gt;You will learn to&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;get started with S3: set up your account, get some tools and get coding&lt;/li&gt;
	&lt;li&gt;upload and download data from S3&lt;/li&gt;
	&lt;li&gt;list all of the files you have in your S3 Buckets&lt;/li&gt;
	&lt;li&gt;add metadata to your objects&lt;/li&gt;
	&lt;li&gt;serve your objects as bit torrents&lt;/li&gt;
	&lt;li&gt;share your data with others (everyone, just a chosen few or nobody at all)&lt;/li&gt;
	&lt;li&gt;backup and restore your pictures, databases or any directory on any computer to S3&lt;/li&gt;
	&lt;li&gt;log who accesses your objects and how often&lt;/li&gt;
	&lt;li&gt;serve assets such as images, MP3s or the static files on your website&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;S3 is built for people like you and me: programmers.  If you feel the itch to create your own library to talk to S3, then chapters 4 and 5 are for you.  Chapter 4 walks you through the S3 authentication process, and builds an S3 authentication library using Test Driven Development.  Chapter 5 builds the beginnings of an S3 library, giving you everything you need to build one of your own, or take the code that&amp;#8217;s in the book and go from there.&lt;/p&gt;
&lt;p&gt;For a complete list of the recipes, see the &lt;a href=&quot;http://leanpub.com/thes3cookbook/toc&quot;&gt;table of contents&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Interested? &lt;a href=&quot;http://leanpub.com//samples/thes3cookbook-sample.pdf&quot;&gt;Download a sample of the book&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All of the code in the book is &lt;a href=&quot;http://github.com/spatten/thes3cookbook&quot;&gt;&lt;span class=&quot;caps&quot;&gt;MIT&lt;/span&gt; licensed and available for download&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;NOTE&lt;/span&gt;:&lt;/p&gt;
&lt;p&gt;The S3 Cookbook is still in beta.  This means that:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;the book is not done&lt;/li&gt;
	&lt;li&gt;Things are still a little rough, but they will improve&lt;/li&gt;
	&lt;li&gt;There will be more recipes coming&lt;/li&gt;
	&lt;li&gt;I need your feedback!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you buy the book, you get updates for free for the lifetime of the book.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>I'll be speaking at RailsConf</title>
   <link href="http://scottpatten.ca/2009/04/i-ll-be-speaking-at-railsconf.html"/>
   <updated>2009-04-20T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2009/04/i-ll-be-speaking-at-railsconf</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m doing a &amp;#8220;Birds of a Feather&amp;#8221; session at RailsConf called &lt;a href=&quot;http://en.oreilly.com/rails2009/public/schedule/detail/9105&quot;&gt;Amazon S3 and Rails &amp;#8211; Take the First Step into the Cloud&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The talk will be 8:00pm on Wednesday, May 6th in Conference Room 10&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s the blurb about the talk:&lt;/p&gt;
&lt;p&gt;Learn how to make your apps faster, more scalable, bullet-proof and just plain cooler with Scott Patten, author of &lt;a href=&quot;http://leanpub.com/thes3cookbook&quot;&gt;The S3 Cookbook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Scott Patten will get you set up to use S3 and get you creating and downloading objects using s3sh, and give a whirlwind tour of its architecture and features.&lt;/p&gt;
&lt;p&gt;We’ll then talk about S3 and its uses for web applications: serving user generated data and assets, backing up your app, authenticated downloads and whatever other crazy things you are using it for. Then we’ll open the floor to a discussion of S3 tips, tricks and pitfalls.&lt;/p&gt;
&lt;p&gt;Hope to see you there!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Searching Beast and WordPress from a Rails app</title>
   <link href="http://scottpatten.ca/2008/05/searching-beast-and-wordpress-from-a-rails-app.html"/>
   <updated>2008-05-17T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2008/05/searching-beast-and-wordpress-from-a-rails-app</id>
   <content type="html">&lt;p&gt;I did some work for &lt;a href=&quot;http://ecolect.net&quot;&gt;ecolect&lt;/a&gt; recently, integrating search across their main site, a Beast forum and a WordPress blog.  It was pretty straightforward once I had it figured out, but I couldn&amp;#8217;t find a walkthrough on the net.&lt;/p&gt;
&lt;p&gt;So, I decided to write one.&lt;/p&gt;
&lt;h2&gt;The Search Engine&lt;/h2&gt;
&lt;p&gt;Ecolect was already using &lt;a href=&quot;http://projects.jkraemer.net/acts_as_ferret/wiki&quot;&gt;acts_as_ferret&lt;/a&gt; for their main site search, so it was a no-brainer to keep using it.  For a fun and thorough introduction to &lt;code&gt;acts_as_ferret&lt;/code&gt;, see the &lt;a href=&quot;http://www.railsenvy.com/2007/2/19/acts-as-ferret-tutorial&quot;&gt;Rails Envy Tutorial&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Searching the Beast Forum&lt;/h2&gt;
&lt;p&gt;(Note: the beast Forum search isn&amp;#8217;t live at the moment as the Forums are not fully functioning yet.)&lt;/p&gt;
&lt;h3&gt;Beast setup&lt;/h3&gt;
&lt;p&gt;In Beast, each Forum has many Topics (saved in the topics table), and each Topic has many Posts (saved in the posts table).&lt;/p&gt;
&lt;p&gt;The Beast forum was set up by &lt;a href=&quot;http://shanti.railsblog.com/&quot;&gt;Shanti Braford&lt;/a&gt; as described in option #3 of this great article on &lt;a href=&quot;http://blog.aisleten.com/2007/07/04/integrating-beast-forum-into-a-ruby-on-rails-app-part-1/&quot;&gt;integrating a beast forum into a Rails app&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this setup, the Beast tables are added to the main site&amp;#8217;s database.  So, the posts and topics tables that we want to search are already in the main site&amp;#8217;s database.  This made things pretty easy: you can search the Beast forum just like you would any database table.&lt;/p&gt;
&lt;h3&gt;Searching a non-integrated Beast forum&lt;/h3&gt;
&lt;p&gt;If you don&amp;#8217;t have the Beast tables integrated in to your main site&amp;#8217;s database, you can still search them.  You just need to point the Topic and Post models to the correct database.  This is a two step process.&lt;/p&gt;
&lt;p&gt;First, set up a database entry for your Beast forum in &lt;code&gt;config/database.yml&lt;/code&gt;.  Something like this:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;beast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mysql&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beast_forum&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;your_password&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localhost&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Then, in the bottom of &lt;code&gt;config/environment.rb&lt;/code&gt;, add the following lines:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;establish_connection&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;beast_forum&amp;quot;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Topic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;establish_connection&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;beast_forum&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;I haven&amp;#8217;t actually tried this, so let me know if you get it working or if you needed to make any changes to what I&amp;#8217;ve written here.&lt;/p&gt;
&lt;h3&gt;The Topic Model&lt;/h3&gt;
&lt;p&gt;Even with the integrated setup there were a few wrinkles.  First, although the Beast tables are in the database, there are no models associated with them.  I wanted to search post body and topic titles, so I created Topic and Post models.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s the Topic model.  It&amp;#8217;s only here so that the Post model can search a posts&amp;#8217;s titles, so there&amp;#8217;s not much to it.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Topic&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt;
    
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3&gt;The Post Model&lt;/h3&gt;
&lt;p&gt;The Post model is a bit more complicated.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:topic&lt;/span&gt;
  
  &lt;span class=&quot;no&quot;&gt;SEARCH_FIELDS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:scrubbed_body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:topic_title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;acts_as_ferret&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:fields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:scrubbed_body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:boost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:yes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; 
                              &lt;span class=&quot;ss&quot;&gt;:topic_title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:boost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:yes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;  
  
  &lt;span class=&quot;kp&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;FullTextSearch&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;# remove the html tags from body&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;scrubbed_body&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;body_html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&amp;lt;\/?[^&amp;gt;]*&amp;gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;topic_title&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      
  &lt;span class=&quot;c1&quot;&gt;# Construct the url to the post    &lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;url&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;http://forums.ecolect.net&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;forums&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forum_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
              &lt;span class=&quot;s2&quot;&gt;&amp;quot;topics&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;#post_&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h4&gt;acts_as_ferret&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;acts_as_ferret&lt;/code&gt; declaration makes the Post model searchable.  Notice that the actual fields being searched are not taken directly from the database; they are both manipulated in some way.  &lt;code&gt;acts_as_ferret&lt;/code&gt; doesn&amp;#8217;t really care if the stuff it is indexing is coming directly from the database or from methods you have added to your model.&lt;/p&gt;
&lt;h4&gt;scrubbing the html tags&lt;/h4&gt;
&lt;p&gt;The post body is stored with &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; tags in them, so I wanted to search and show the posts with tags scrubbed out of them.  This is done using the &lt;code&gt;Post#scrubbed_body&lt;/code&gt; method, which is just an ugly regexp that takes out anything between &amp;lt; and &amp;gt; signs.&lt;/p&gt;
&lt;h4&gt;the url method&lt;/h4&gt;
&lt;p&gt;I also wanted to link to the posts, so I created a &lt;code&gt;Post#url&lt;/code&gt; method which is used in the view.&lt;/p&gt;
&lt;p&gt;Finally, the actual search is done using the &lt;code&gt;FullTextSearch&lt;/code&gt; mixin, which adds a class method &lt;code&gt;Post::full_text_search&lt;/code&gt; to &lt;code&gt;Post&lt;/code&gt;.  The &lt;code&gt;FullTextSearch&lt;/code&gt; mixin is described in more detail below.&lt;/p&gt;
&lt;h2&gt;Searching the WordPress Blog&lt;/h2&gt;
&lt;p&gt;The only table from the WordPress Blog that you really care about is the &lt;code&gt;wp_post&lt;/code&gt; table.  To get access to it in your Rails app, make a &lt;code&gt;WpPost&lt;/code&gt; model and point it at your WordPress db.&lt;/p&gt;
&lt;p&gt;First, create a database entry in &lt;code&gt;config/database.yml&lt;/code&gt; that looks like this:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;wordpress&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;mysql&lt;/span&gt;
  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;database&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;wordpress&lt;/span&gt;
  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;app&lt;/span&gt;
  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;your_password&lt;/span&gt;
  &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l l-Scalar l-Scalar-Plain&quot;&gt;localhost&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Then, add the following line to the bottom of &lt;code&gt;config/environment.rb&lt;/code&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;WpPost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;establish_connection&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;wordpress&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Here&amp;#8217;s the model:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WpPost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;primary_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ID&amp;quot;&lt;/span&gt;
  
  &lt;span class=&quot;no&quot;&gt;SEARCH_FIELDS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:scrubbed_title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:scrubbed_content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
                   
  &lt;span class=&quot;n&quot;&gt;acts_as_ferret&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:fields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:scrubbed_title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:boost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:yes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                              &lt;span class=&quot;ss&quot;&gt;:scrubbed_content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:boost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:yes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
  
  &lt;span class=&quot;kp&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;FullTextSearch&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;id&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;read_attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;# title and content need to have the html tags removed from them, and should&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# only be searchable if the post has been assigned a url (the guid) and the post &lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# is actually a post and not an asset.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;scrubbed_title&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;post_title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&amp;lt;\/?[^&amp;gt;]*&amp;gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;guid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;scrubbed_content&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;post_content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&amp;lt;\/?[^&amp;gt;]*&amp;gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;post_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;post&amp;quot;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;guid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;There are a few things to note here:&lt;/p&gt;
&lt;p&gt;WordPress uses &lt;code&gt;ID&lt;/code&gt;, rather than &lt;code&gt;id&lt;/code&gt;, as its primary key.  The line &lt;code&gt;primary_key = &quot;ID&quot;&lt;/code&gt; lets Rails know about that.  You also need to add an &lt;code&gt;id&lt;/code&gt; method that returns &lt;code&gt;ID&lt;/code&gt; to get ferret indexing things properly.&lt;/p&gt;
&lt;p&gt;You will need to scrub the html tags from the content and title; that&amp;#8217;s what the &lt;code&gt;scrubbed_title&lt;/code&gt; and &lt;code&gt;scrubbed_content&lt;/code&gt; methods do.&lt;/p&gt;
&lt;p&gt;Finally, you don&amp;#8217;t want search results to index assets (which are stored in the wp_post model as well) or any un-published posts.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Real posts will have a &lt;code&gt;post_type&lt;/code&gt; of &lt;code&gt;&#39;post&#39;&lt;/code&gt;.&lt;/li&gt;
	&lt;li&gt;An unpublished post won&amp;#8217;t have its guid set.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is taken care of by only returning titles or content &lt;code&gt;if post_type == &quot;post&quot; and !guid.empty?&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The FullTextSearch mixin&lt;/h2&gt;
&lt;p&gt;This is based on code by &lt;a href=&quot;http://blog.zmok.net/articles/2006/10/18/full-text-search-in-ruby-on-rails-3-ferret&quot;&gt;Roman Mackovcak&amp;#8217;s article on full text search in Rails&lt;/a&gt;.  All I did was extract the method he provides out in to a mixin so I could use it in multiple models.&lt;/p&gt;
&lt;p&gt;To use the mixin in a model, the model needs to define &lt;code&gt;SEARCH_FIELDS&lt;/code&gt; and have an &lt;code&gt;acts_as_ferret&lt;/code&gt;  declaration.  &lt;code&gt;SEARCH_FIELDS&lt;/code&gt; is an array of symbols giving the model fields to be searched.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;FullTextSearch&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;##&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# FERRET SEARCH METHOD&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# This method requires that you set the following in the model:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# SEARCH_FIELDS: &lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# a list of symbols giving the fields to be searched.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# E.g., SEARCH_FIELDS = [:post_title, :post_content]&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# The acts_as_ferret declaration.  &lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Use :store =&amp;gt; :yes for each field if you want to use highlighting for that field.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# E.g., &lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# acts_as_ferret :fields =&amp;gt; { :post_title =&amp;gt; {:boost =&amp;gt; 3, :store =&amp;gt; :yes},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;#                             :post_content =&amp;gt; {:boost =&amp;gt; 0, :store =&amp;gt; :yes}}&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;##&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;DEFAULT_PER_PAGE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;full_text_search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
     
     &lt;span class=&quot;n&quot;&gt;default_options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:limit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;FullTextSearch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;DEFAULT_PER_PAGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                        &lt;span class=&quot;ss&quot;&gt;:page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                        &lt;span class=&quot;ss&quot;&gt;:lazy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;const_get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:SEARCH_FIELDS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                       &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default_options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;

     &lt;span class=&quot;c1&quot;&gt;# Get the offset based on what page we&amp;#39;re on&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:offset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:limit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  
     &lt;span class=&quot;c1&quot;&gt;# Now do the query with our options&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find_by_contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

     &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;total_hits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;  
  
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;You use it like this:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;WpPost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;full_text_search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;WpPost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;full_text_search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:limit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;The &lt;code&gt;full_text_search&lt;/code&gt; method returns an array of length two.  The first value in the array is the number of search results, and the second value the actual search results.&lt;/p&gt;
&lt;h3&gt;Re-indexing the non-local models&lt;/h3&gt;
&lt;p&gt;As Ruben pointed out in the comments, I forgot to mention how I deal with re-indexing the WordPress and Beast database tables.  This is necessary as these tables have data that is modified by another application, so your Rails app doesn&amp;#8217;t know that changes have been made to them.&lt;/p&gt;
&lt;p&gt;To deal with this, I wrote a simple Rake task that reindexes the &lt;code&gt;WpPost&lt;/code&gt;, &lt;code&gt;WpArticle&lt;/code&gt; and &lt;code&gt;Post&lt;/code&gt; models, and then added a line to the &lt;code&gt;crontab&lt;/code&gt; to run it hourly.  Here&amp;#8217;s the rake file, which I put in &lt;code&gt;RAILS_ROOT/lib/tasks/ferret.rake&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ferret&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;rebuild the non-local Ferret indices, as these need to be done manually.&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rebuild_nonlocal_indices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:environment&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;WpPost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;WpArticle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;rebuilding &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; index&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rebuild_index&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;    
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;and, for posterity, here&amp;#8217;s the crontab line:&lt;/p&gt;
&lt;pre&gt;
20 * * * *  cd &amp;lt;rails_root&amp;gt; &amp;amp;&amp;amp; /usr/local/bin/rake ferret:rebuild_nonlocal_indices &amp;gt;&amp;gt; &amp;lt;log_directory&amp;gt;/ferret_reindex.log  2&amp;gt;&amp;amp;1
&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Rubyize this: Live in Vancouver.  Refactoring #1.</title>
   <link href="http://scottpatten.ca/2008/01/rubyize-this-live-in-vancouver.html"/>
   <updated>2008-01-27T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2008/01/rubyize-this-live-in-vancouver</id>
   <content type="html">&lt;p&gt;At &lt;a href=&quot;rubycamp.wordpress.com&quot;&gt;rubycamp&lt;/a&gt; today, I ran a little &lt;a href=&quot;http://rubycamp.wordpress.com/2008/01/01/rubyizethis/&quot;&gt;Rubyize This&lt;/a&gt; workshop.  Rubyize This is a game invented by &lt;a href=&quot;http://www.rubyfleebie.com/about-me/&quot;&gt;François Lamontagne&lt;/a&gt;.  The idea is that someone puts up a chunk of code that is written in Ruby, but in a not very Rubyish way. Then, everyone in the audience gets to Rubyize it!&lt;/p&gt;
&lt;p&gt;We tried to use the most excellent &lt;a href=&quot;http://refactormycode.com/&quot;&gt;RefactorMyCode.com&lt;/a&gt;, but the WiFi was too saturated so we had to resort to posting the code on my blog and people plugging their laptops in to the projector to present their results.&lt;/p&gt;
&lt;p&gt;So, this post and the following two will show the original code.  Keep in mind that this is intentionally ugly!&lt;/p&gt;
&lt;p&gt;We had some great refactorings.  If you were at the workshop, please post your refactorings in the comments.  I&amp;#8217;ll make the pretty and put them in the posting.&lt;/p&gt;
&lt;p&gt;The other two refactorings are at &lt;a href=&quot;2008/01/rubyize-this-live-in-vancouver-refactoring-2.html&quot;&gt;Rubyize this #2&lt;/a&gt; and &lt;a href=&quot;2008/01/rubyize-this-live-in-vancouver-refactoring-3.html&quot;&gt;Rubyize this #3&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Without further ado, here&amp;#8217;s the first refactoring.  The code is supposed to create a file filled with random numbers, one number per line.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# create num random numbers between min and max &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# and print them to a file called file_name, one per line&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create_random_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;min&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;   
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;create_random_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;random.txt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Here&amp;#8217;s the first refactoring:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create_random_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
  &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; 
    &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;upto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;min&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; 
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Here&amp;#8217;s one from &lt;a href=&quot;http://timestream.net/nonsequitur&quot;&gt;Sam Livingston-Gray&lt;/a&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# create num random numbers between min and max &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# and print them to a file called file_name, one per line&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Range&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;random_member&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create_random_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;times&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random_member&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;create_random_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;random.txt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Here&amp;#8217;s what I came up with:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create_random_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;times&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;create_random_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;random.txt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;</content>
 </entry>
 
 <entry>
   <title>Rubyize This: Live in Vancouver.  Refactoring #3</title>
   <link href="http://scottpatten.ca/2008/01/rubyize-this-live-in-vancouver-refactoring-3.html"/>
   <updated>2008-01-27T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2008/01/rubyize-this-live-in-vancouver-refactoring-3</id>
   <content type="html">&lt;p&gt;Here&amp;#8217;s the final refactoring from the Rubyize This workshop.  See the &lt;a href=&quot;/2008/01/rubyize-this-live-in-vancouver.html&quot;&gt;first refactoring&lt;/a&gt; for an explanation of what&amp;#8217;s going on and why this code is so darn ugly!  The &lt;a href=&quot;/2008/01/rubyize-this-live-in-vancouver-refactoring-2.html&quot;&gt;second refactoring&lt;/a&gt; is worth checking out as well.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;delete_large_files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;# Make sure directory ends in a slash&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/\/$/&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;# Find all of the files in the directory &lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;files&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;glob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;*&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;# Delete all files with size larger than max_size&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;files&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# 50 kb&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;./files_to_delete&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;delete_large_files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;This was the final refactoring, and the end of the conference, so we sort of ran out of time.&lt;/p&gt;
&lt;p&gt;I didn&amp;#8217;t get a change to show off my solution.  Here it is.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;delete_large_files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;files_to_delete&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;glob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;*&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_size&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;files_to_delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;What&amp;#8217;s going on with that &lt;code&gt;File.delete&lt;/code&gt; call?&lt;/p&gt;
&lt;p&gt;First, &lt;code&gt;File.delete&lt;/code&gt; takes multiple arguments and deletes all of them.&lt;/p&gt;
&lt;p&gt;Second, I used the asterisk operator.  From &lt;a href=&quot;http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Method_Calls&quot;&gt;here&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;The asterisk operator may also precede an Array argument in a method call. In this case the Array will be expanded and the values passed in as if they were separated by commas.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I don&amp;#8217;t think I&amp;#8217;ve every actually used the asterisk operator in production code, but it sure came in handy here.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Rubyize This: Live in Vancouver.  Refactoring #2</title>
   <link href="http://scottpatten.ca/2008/01/rubyize-this-live-in-vancouver-refactoring-2.html"/>
   <updated>2008-01-27T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2008/01/rubyize-this-live-in-vancouver-refactoring-2</id>
   <content type="html">&lt;p&gt;Here&amp;#8217;s the second refactoring from the Rubyize This workshop.  See the &lt;a href=&quot;/2008/01/rubyize-this-live-in-vancouver.html&quot;&gt;first refactoring&lt;/a&gt; for an explanation of what&amp;#8217;s going on and why this code is so darn ugly!  Don&amp;#8217;t forget to check out the  &lt;a href=&quot;/2008/01/rubyize-this-live-in-vancouver-refactoring-3.html&quot;&gt;third and final refactoring&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This script loads the file full of random numbers from &lt;a href=&quot;/2008/01/rubyize-this-live-in-vancouver.html&quot;&gt;the first refactoring&lt;/a&gt; and makes a beautiful ascii-art histogram from it.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;pp&amp;#39;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;BIG_NUMBER&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32768&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Get data from a file, turn it in to a float, and find the max&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readlines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;random.txt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;BIG_NUMBER&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chomp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_f&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# max is ceil(max(data[n]))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Create the empty histogram&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Fill the histogram&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Print the histogram&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;*&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Here&amp;#8217;s a very concise one-liner from the crowd:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;upto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readlines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;random.txt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chomp!&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Here&amp;#8217;s &lt;a href=&quot;http://exortech.com/blog/&quot;&gt;Owen&amp;#8217;s&lt;/a&gt; refactoring:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;pp&amp;#39;&lt;/span&gt; 
&lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; 
&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readlines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;random.txt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chomp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; 
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; 

&lt;span class=&quot;c1&quot;&gt;# Print the histogram &lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt; 
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; 
&lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;*&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Here&amp;#8217;s &lt;a href=&quot;http://timestream.net/nonsequitur&quot;&gt;Sam Livingstone Gray&amp;#8217;s&lt;/a&gt; refactoring&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;pp&amp;#39;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Get data from a file, turn it in to a float, and find the max&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Enumerable&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;value_counts&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
    &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;lines&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readlines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;random.txt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chomp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value_counts&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Print the histogram&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;*&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;I really like this one.  Sam created a simple extension to Enumerable that I can see using over and over again.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s what I came up with, with some debugging help from the group&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;pp&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readlines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;random.txt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chomp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;datum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;pp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;histogram&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;*&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;</content>
 </entry>
 
 <entry>
   <title>Adding json responses to all of your controller actions</title>
   <link href="http://scottpatten.ca/2008/01/adding-json-responses-to-all-of-your-controller-actions.html"/>
   <updated>2008-01-14T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2008/01/adding-json-responses-to-all-of-your-controller-actions</id>
   <content type="html">&lt;p&gt;Gerald has decided to use &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt; responses for the mobile phone app&lt;br /&gt;
we&amp;#8217;ll be building at the &lt;a href=&quot;http://www.railsadvance.com/workshop/jan-08-intermediate&quot;&gt;intermediate Rails&lt;br /&gt;
workshop&lt;/a&gt;.&lt;br /&gt;
I&amp;#8217;m a lazy guy by nature, so there was no way I was going to paste in&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@bookmark&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;in to very controller method.&lt;/p&gt;
&lt;p&gt;Now, the easiest way to do this would be to add &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt; response to the scaffolding.  The templates are in &lt;code&gt;RAILS_ROOT/vendor/rails/lib/rails_generator/generators/components/scaffold/&lt;/code&gt;.  Open up the &lt;code&gt;controller.rb&lt;/code&gt; template and add in the &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt; response shown above to the index, show, update and destroy methods and you&amp;#8217;re done.&lt;/p&gt;
&lt;p&gt;Unfortunately, I had already mostly developed the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; when I realized that I had to add in the &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt; responses (It&amp;#8217;s not Gerald&amp;#8217;s fault, he told me long ago).  So, I decided to write a quick rake task to do the job for me.  To use it, create a file called &lt;code&gt;add_json.rake&lt;/code&gt; in &lt;code&gt;RAILS_ROOT/lib/tasks&lt;/code&gt; and copy the following code in to it:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rails&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Adds a &amp;#39;format.json ...&amp;#39; line for each &amp;#39;format.xml ...&amp;#39; line in every controller&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:add_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:get_controller_list&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@controllers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;new_lines&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readlines&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collect&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^\s+format\.xml/&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/xml/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;json&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flatten&lt;/span&gt;
        
      &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_lines&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:get_controller_list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:environment&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@controllers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;glob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RAILS_ROOT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;app&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;controllers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;*_controller.rb&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Call the task from &lt;code&gt;RAILS_ROOT&lt;/code&gt; like this:&lt;br /&gt;
&lt;code&gt;rake rails:add_json&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The task opens up every controller, and every time it finds a line that starts with &lt;code&gt;format.xml&lt;/code&gt;, it makes a copy of that line just below with every instance of &amp;#8216;xml&amp;#8217; replaced with &amp;#8216;json&amp;#8217;.  It&amp;#8217;s &lt;del&gt;pretty&lt;/del&gt; very brain-dead: it doesn&amp;#8217;t check if the json response is already there, so don&amp;#8217;t run it twice on the same project.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Fun with Single Table Inheritance</title>
   <link href="http://scottpatten.ca/2007/12/fun-with-single-table-inheritance.html"/>
   <updated>2007-12-31T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2007/12/fun-with-single-table-inheritance</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m working on the sample application for the &lt;a href=&quot;http://www.railsadvance.com/workshop/jan-08-intermediate&quot;&gt;Intermediate Ruby on Rails Workshop&lt;/a&gt; that &lt;a href=&quot;http://geraldbauer.wordpress.com&quot;&gt;Gerald Bauer&lt;/a&gt; and I are putting on in January.  I had to remind myself of some of the foibles of Single Table Inheritance (&lt;span class=&quot;caps&quot;&gt;STI&lt;/span&gt;).  I thought others might find this useful, so here&amp;#8217;s what I found.&lt;/p&gt;
&lt;h3&gt;The Set-up&lt;/h3&gt;
&lt;p&gt;I have two types of posts in the application I&amp;#8217;m building: posts by people with an empty room looking for a roomie (RoomiePosts), and posts by people looking for a room (RoomPosts).  They both share a lot of the same attributes, so it&amp;#8217;s not very &lt;a href=&quot;http://en.wikipedia.org/wiki/Don&amp;#39;t_repeat_yourself&quot;&gt;&lt;span class=&quot;caps&quot;&gt;DRY&lt;/span&gt;&lt;/a&gt; to create two separate models.&lt;/p&gt;
&lt;p&gt;This is where Single Table Inheritance comes in.  &lt;span class=&quot;caps&quot;&gt;STI&lt;/span&gt; is basically a way of subclassing a single model, creating subclasses that all use the same database table.&lt;/p&gt;
&lt;p&gt;What I did is create a Post model and two subclasses: RoomiePost and RoomPost.  Here&amp;#8217;s how you do it.&lt;/p&gt;
&lt;h3&gt;Creating the Database Table&lt;/h3&gt;
&lt;p&gt;Here&amp;#8217;s the migration for the posts database table.  Note that this uses the new migrations syntax in Rails 2.0.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CreatePosts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Migration&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;up&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;create_table&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;integer&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rent&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:start_date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:expiry_date&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:includes_utilities&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:type&lt;/span&gt;
      
      &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timestamps&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;down&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;drop_table&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Most of the columns are pretty straightforward.  &lt;code&gt;text&lt;/code&gt; will contain the text of the post.  &lt;code&gt;start_date&lt;/code&gt; and &lt;code&gt;expiry_date&lt;/code&gt; will determine when the post will start and stop being shown on the site.  &lt;code&gt;rent&lt;/code&gt; and &lt;code&gt;includes_utilities&lt;/code&gt; will only be used by the RoomiePost subclass, but still need to be created for all subclasses of the Post model.&lt;/p&gt;
&lt;p&gt;The interesting column is &lt;code&gt;type&lt;/code&gt;.  This allows Rails to determine which subclass the row should be loaded in to.  If you set &lt;code&gt;type = &quot;RoomiePost&quot;&lt;/code&gt;, then it&amp;#8217;s a RoomiePost.  If you set &lt;code&gt;type = &quot;RoomPost&quot;&lt;/code&gt;, then it&amp;#8217;s a RoomPost.&lt;/p&gt;
&lt;h3&gt;Creating the Models&lt;/h3&gt;
&lt;p&gt;You need to create a Post, RoomiePost and RoomPost model.  They look like this:&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;/app/models/post.rb&lt;/code&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt; 
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;In &lt;code&gt;/app/models/roomie_post.rb&lt;/code&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoomiePost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;In &lt;code&gt;/app/models/room_post.rb&lt;/code&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoomPost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Note that RoomiePost and RoomPost are both subclasses of the Post model.  Here&amp;#8217;s where you run in to a &amp;#8220;gotcha&amp;#8221;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You have to create the models in separate files&lt;/strong&gt;.  If you don&amp;#8217;t, Rails ignores the subclassed models.&lt;/p&gt;
&lt;p&gt;For more information, and another workaround, see &lt;a href=&quot;http://bjhess.com/bjhessblog/2007/10/15/when-single-table-inheritance-attacks/&quot;&gt;this blog post&lt;/a&gt;.  The comment by Chris at the bottom gives the &amp;#8216;create the models in separate files&amp;#8217; solution.&lt;/p&gt;
&lt;p&gt;Okay, so now you have the models all set up.  You can do things like&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RoomiePost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:rent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:includes_utilities&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Great room in a shared house in the Commercial Drive area&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;And it will create a row in the &lt;code&gt;posts&lt;/code&gt; table with &lt;code&gt;type = &quot;RoomiePost&quot;&lt;/code&gt;.  If you have 5 RoomiePosts and 2 RoomPosts, then Posts.count will return 7.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RoomiePost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;           
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RoomPost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3&gt;Adding behaviour to &lt;span class=&quot;caps&quot;&gt;STI&lt;/span&gt; models&lt;/h3&gt;
&lt;p&gt;I want to be able to determine if a post is active by looking at the start and expiry dates, and to get a list of all active posts, roomie_posts and room_posts.  I also want to have a different icon for each post type.&lt;/p&gt;
&lt;p&gt;The Post.active_post? and Post::active_posts methods are straight-forward:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_active?&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expiry_date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; 
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;active_posts&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_active?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;  
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;The only tricky part is that I used &lt;code&gt;self.find(:all)&lt;/code&gt; instead of &lt;code&gt;Post.find(:all)&lt;/code&gt; in the Post::active_posts method.  This makes sure that RoomiePost::active_posts only returns RoomiePosts and RoomPost::active_posts only returns RoomPosts.&lt;/p&gt;
&lt;p&gt;Getting the icon to work took a little more figuring out.  If I wanted to do this in straight-up Ruby, I&amp;#8217;d do something like&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;ICON_PATH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;icons&amp;quot;&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@icon_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;base.gif&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;icon&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ICON_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@icon_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoomiePost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@icon_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;roomie.gif&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoomPost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@icon_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;room.gif&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Then I could do this&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;$&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;irb&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subclass_test&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;irb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;001&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;icon&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;icons/base.gif&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;irb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;002&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RoomiePost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;icon&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;icons/roomie.gif&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;irb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;003&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RoomPost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;icon&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;icons/room.gif&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;This doesn&amp;#8217;t quite work in the Rails version.  Not to worry, you only have to make one simple change:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;replace the &lt;code&gt;initialize&lt;/code&gt; method with an &lt;code&gt;after_initialize&lt;/code&gt; callback.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The final &lt;code&gt;post.rb&lt;/code&gt;, &lt;code&gt;roomie_post.rb&lt;/code&gt; and &lt;code&gt;room_post.rb&lt;/code&gt; files look like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;post.rb&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;ICON_PATH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/images/icons&amp;quot;&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;after_initialize&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@icon_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;base.gif&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;icon&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ICON_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@icon_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;  
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_active?&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;..&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expiry_date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; 
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;active_posts&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_active?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;  
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;&lt;code&gt;roomie_post.rb&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoomiePost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;after_initialize&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@icon_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;roomie.gif&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;&lt;code&gt;room_post.rb&lt;/code&gt;:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoomPost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;after_initialize&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@icon_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;room.gif&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;One final note:  because of the way the &lt;code&gt;after_initialize&lt;/code&gt; callback works, you have to actually define an &lt;code&gt;after_initialize&lt;/code&gt; method.  You can&amp;#8217;t do something like this:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoomiePost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;after_initialize&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:set_icon_name&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set_icon_name&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@icon_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;roomie.gif&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;If you want to learn more about &lt;span class=&quot;caps&quot;&gt;STI&lt;/span&gt;, and a whole slew of other info on Rails, sign up for the &lt;a href=&quot;http://www.railsadvance.com/workshop/jan-08-intermediate&quot;&gt;Intermediate Rails Workshop&lt;/a&gt; on January 25th, 2008 in Vancouver.&lt;/p&gt;
&lt;p&gt;Early Bird rates are available until January 9th!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>RubyCamp Vancouver</title>
   <link href="http://scottpatten.ca/2007/12/rubycamp-vancouver.html"/>
   <updated>2007-12-19T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2007/12/rubycamp-vancouver</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://rubycamp.wordpress.com&quot;&gt;RubyCamp&lt;/a&gt; is a free one-day gathering for Rubyists and Railsers.&lt;/p&gt;
&lt;h4&gt;When and Where&lt;/h4&gt;
&lt;p&gt;WorkSpace in downtown Vancouver, B.C., Canada &lt;br/&gt;
January 26th, 2008 from 9:00 to 5:00&lt;/p&gt;
&lt;h4&gt;Who should come&lt;/h4&gt;
&lt;p&gt;Anyone who’s interested in Ruby and Rails, whether you’re just interested in learning what this Ruby thing is all about or you know Ruby inside out.&lt;/p&gt;
&lt;h4&gt;The Conference Track&lt;/h4&gt;
&lt;p&gt;A conference-style track with “classic” talks on Ruby or Rails topics. We’re looking for a few more speakers, so see &lt;a href=&quot;http://rubycamp.wordpress.com/about/#talks&quot;&gt;here&lt;/a&gt; if you’re interested in giving a talk.&lt;/p&gt;
&lt;h4&gt;The Hackathon Track&lt;/h4&gt;
&lt;p&gt;An informal un-conference track focusing on hacking some Ruby code, showing off a cool feature you just added to your Rails application or demonstrating a new addition to Rails 2.0.&lt;/p&gt;
&lt;p&gt;If you’re interested in working on some code or showing off something, get started by &lt;a href=&quot;http://rubycamp.wordpress.com/about/#hackathon&quot;&gt;promoting your ideas and getting some buzz going&lt;/a&gt; .&lt;/p&gt;
&lt;h4&gt;A weekend of Ruby&lt;/h4&gt;
&lt;p&gt;There are two more reasons to come to Vancouver for those of you who are out of town.&lt;/p&gt;
&lt;p&gt;On the Friday before RubyCamp, Rails Advance is giving a one day &lt;a href=&quot;http://railsadvance.com/workshop&quot;&gt;intermediate Ruby and Rails workshop&lt;/a&gt;.   (Rails Advance is Gerald Bauer and I, by the way)&lt;/p&gt;
&lt;p&gt;On the Sunday after RubyCamp, Peter Armstrong is giving a one day workshop on &lt;a href=&quot;http://www.flexiblerails.com/workshops&quot;&gt;Flex and Rails&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more information, see the &lt;a href=&quot;http://rubycamp.wordpress.com&quot;&gt;RubyCamp web site&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;See you all at RubyCamp in Vancouver!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Amazon S3, Ruby and Rails slides</title>
   <link href="http://scottpatten.ca/2007/12/amazon-s3-ruby-and-rails-slides.html"/>
   <updated>2007-12-05T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2007/12/amazon-s3-ruby-and-rails-slides</id>
   <content type="html">&lt;p&gt;The slides from the talk are &lt;a href=&quot;http://spatten_presentations.s3.amazonaws.com/s3-on-rails.pdf&quot;&gt;here&lt;/a&gt;.  (Yes, they&amp;#8217;re hosted on S3).&lt;/p&gt;
&lt;p&gt;There are two points in the presentation where I switched to a different window.&lt;/p&gt;
&lt;p&gt;At the &amp;#8216;S3SH &lt;span class=&quot;caps&quot;&gt;DEMO&lt;/span&gt;&amp;#8217; slide, I did some live coding showing how you can work with S3 using s3sh.  It basically followed the script shown in &amp;#8216;s3sh demo script&amp;#8217; below, so read that part when you see the &amp;#8216;S3SH &lt;span class=&quot;caps&quot;&gt;DEMO&lt;/span&gt;&amp;#8217; slide.&lt;/p&gt;
&lt;p&gt;At the &amp;#8216;Example: S3Syncer&amp;#8217; slide, I switched over to textmate and showed the code for a simple script to synchronize a single directory to S3.  I then demoed the script to show it working.  So, when you see the &amp;#8216;Example; S3Syncer&amp;#8217; slide, read the s3syncer code and s3syncer demo sections below.&lt;/p&gt;
&lt;h2&gt;s3sh demo script&lt;/h2&gt;
&lt;p&gt;Start up s3sh&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
$&amp;gt; s3sh&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Create a bucket.&lt;br /&gt;
Show that you can create a bucket multiple times if you own it, but trying to create a bucket that somebody else owns raises an error.&lt;/p&gt;
&lt;pre&gt;
&amp;gt;&amp;gt; Bucket.create(&#39;spatten_s3demo&#39;)
=&amp;gt; true
&amp;gt;&amp;gt; Bucket.create(&#39;spatten_s3demo&#39;)
=&amp;gt; true
&amp;gt;&amp;gt; Bucket.create(&#39;test&#39;)
AWS::S3::BucketAlreadyExists: The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.
        from /usr/local/lib/ruby/gems/1.8/gems/aws-s3-0.4.0/bin/../lib/aws/s3/error.rb:38:in `raise&#39;
        from /usr/local/lib/ruby/gems/1.8/gems/aws-s3-0.4.0/bin/../lib/aws/s3/base.rb:72:in `request&#39;
        from /usr/local/lib/ruby/gems/1.8/gems/aws-s3-0.4.0/bin/../lib/aws/s3/base.rb:83:in `put&#39;
        from /usr/local/lib/ruby/gems/1.8/gems/aws-s3-0.4.0/bin/../lib/aws/s3/bucket.rb:79:in `create&#39;
        from (irb):3
&lt;/pre&gt;
&lt;p&gt;You can save a bucket in a variable using &lt;code&gt;Bucket.find&lt;/code&gt;&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
&amp;gt;&amp;gt; b = Bucket.find(&amp;#8216;spatten_s3demo&amp;#8217;)&lt;br /&gt;
=&amp;gt; #&amp;lt;&lt;span class=&quot;caps&quot;&gt;AWS&lt;/span&gt;::S3::Bucket:0&amp;#215;14ae7b8 @attributes={&amp;quot;prefix&amp;quot;=&amp;gt;nil, &amp;#8220;name&amp;#8221;=&amp;gt;&amp;quot;spatten_s3demo&amp;quot;, &amp;#8220;marker&amp;#8221;=&amp;gt;nil, &amp;#8220;max_keys&amp;#8221;=&amp;gt;1000, &amp;#8220;is_truncated&amp;#8221;=&amp;gt;false, &amp;#8220;xmlns&amp;#8221;=&amp;gt;&amp;quot;http://s3.amazonaws.com/doc/2006-03-01/&amp;quot;}, @object_cache=[]&amp;gt;&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Create a text object&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
&amp;gt;&amp;gt; S3Object.store(&amp;#8216;test.txt&amp;#8217;, &amp;#8216;This is a test&amp;#8217;, &amp;#8216;spatten_s3demo&amp;#8217;)&lt;br /&gt;
=&amp;gt; #&lt;AWS::S3::S3Object::Response:0x10830590 200 OK&gt;&lt;br /&gt;
&amp;gt;&amp;gt; b.objects&lt;br /&gt;
=&amp;gt; [#&amp;lt;&lt;span class=&quot;caps&quot;&gt;AWS&lt;/span&gt;::S3::S3Object:0&amp;#215;10804170 &amp;#8216;/spatten_s3demo/test.txt&amp;#8217;&amp;gt;]&lt;br /&gt;
&amp;gt;&amp;gt; pp b.objects&lt;sup class=&quot;footnote&quot; id=&quot;fnr0&quot;&gt;&lt;a href=&quot;#fn0&quot;&gt;0&lt;/a&gt;&lt;/sup&gt;.about&lt;br /&gt;
{&amp;quot;last-modified&amp;quot;=&amp;gt;&amp;quot;Wed, 05 Dec 2007 19:56:49 GMT&amp;quot;,&lt;br /&gt;
 &amp;#8220;x-amz-id-2&amp;#8221;=&amp;gt;&lt;br /&gt;
  &amp;#8220;JACm9T+m9CgZhmj4q6q00OSGHgSyBVAbQ1cgRWGydYZLTKdhLc/IUZ+K7b/1snOc&amp;#8221;,&lt;br /&gt;
 &amp;#8220;content-type&amp;#8221;=&amp;gt;&amp;quot;text/plain&amp;quot;,&lt;br /&gt;
 &amp;#8220;etag&amp;#8221;=&amp;gt;&amp;quot;\&amp;#8220;ce114e4501d2f4e2dcea3e17b546f339\&amp;#8221;&amp;quot;,&lt;br /&gt;
 &amp;#8220;date&amp;#8221;=&amp;gt;&amp;quot;Wed, 05 Dec 2007 19:57:03 GMT&amp;quot;,&lt;br /&gt;
 &amp;#8220;x-amz-request-id&amp;#8221;=&amp;gt;&amp;quot;CA170D2AA5DEB0C9&amp;quot;,&lt;br /&gt;
 &amp;#8220;server&amp;#8221;=&amp;gt;&amp;quot;AmazonS3&amp;quot;,&lt;br /&gt;
 &amp;#8220;content-length&amp;#8221;=&amp;gt;&amp;quot;14&amp;quot;}&lt;br /&gt;
=&amp;gt; nil&lt;br /&gt;
&amp;gt;&amp;gt; b.objects&lt;sup class=&quot;footnote&quot; id=&quot;fnr0&quot;&gt;&lt;a href=&quot;#fn0&quot;&gt;0&lt;/a&gt;&lt;/sup&gt;.key&lt;br /&gt;
=&amp;gt; &amp;#8220;test.txt&amp;#8221;&lt;br /&gt;
&amp;gt;&amp;gt; b.objects&lt;sup class=&quot;footnote&quot; id=&quot;fnr0&quot;&gt;&lt;a href=&quot;#fn0&quot;&gt;0&lt;/a&gt;&lt;/sup&gt;.value&lt;br /&gt;
=&amp;gt; &amp;#8220;This is a test&amp;#8221;&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Create a binary object and show it in a browser&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
&amp;gt;&amp;gt; S3Object.store(&amp;#8216;vampire.jpg&amp;#8217;, File.open(&amp;#8216;vampire.jpg&amp;#8217;), &amp;#8216;spatten_s3demo&amp;#8217;)&lt;br /&gt;
=&amp;gt; #&lt;AWS::S3::S3Object::Response:0x10764700 200 OK&gt;&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Show the photo in browser&lt;/p&gt;
&lt;p&gt;This doesn&amp;#8217;t work, as the file is only readable by me.  Make it public readable and do it again.&lt;/p&gt;
&lt;pre&gt;
&amp;gt;&amp;gt; S3Object.store(&#39;vampire.jpg&#39;, File.open(&#39;vampire.jpg&#39;), &#39;spatten_s3demo&#39;, 
     :access =&amp;gt; :public_read)
=&amp;gt; #&amp;lt;AWS::S3::S3Object::Response:0x10747950 200 OK&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Show it in a browser again.  It works this time.&lt;/p&gt;
&lt;p&gt;Look at bucket.objects.  We have to reload the bucket to show the new object.&lt;/p&gt;
&lt;pre&gt;
&amp;gt;&amp;gt; b.objects
=&amp;gt; [#&amp;lt;AWS::S3::S3Object:0x10804170 &#39;/spatten_s3demo/test.txt&#39;&amp;gt;]
&amp;gt;&amp;gt; b.objects(:reload)
=&amp;gt; [#&amp;lt;AWS::S3::S3Object:0x10708080 &#39;/spatten_s3demo/test.txt&#39;&amp;gt;, #&amp;lt;AWS::S3::S3Object:0x10708070 &#39;/spatten_s3demo/vampire.jpg&#39;&amp;gt;]
&lt;/pre&gt;
&lt;p&gt;Hash access to bucket objects&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
&amp;gt;&amp;gt; b[&amp;#8216;vampire.jpg&amp;#8217;]&lt;br /&gt;
=&amp;gt; #&amp;lt;&lt;span class=&quot;caps&quot;&gt;AWS&lt;/span&gt;::S3::S3Object:0&amp;#215;10708070 &amp;#8216;/spatten_s3demo/vampire.jpg&amp;#8217;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt; vamp = b[&amp;#8216;vampire.jpg&amp;#8217;]&lt;br /&gt;
=&amp;gt; #&amp;lt;&lt;span class=&quot;caps&quot;&gt;AWS&lt;/span&gt;::S3::S3Object:0&amp;#215;10708070 &amp;#8216;/spatten_s3demo/vampire.jpg&amp;#8217;&amp;gt;&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;A look at metadata&lt;/p&gt;
&lt;pre&gt;
&amp;gt;&amp;gt; vamp.content_type
=&amp;gt; &quot;image/jpeg&quot;
&amp;gt;&amp;gt; vamp.size
=&amp;gt; 10817
&amp;gt;&amp;gt; vamp.metadata
=&amp;gt; {}
&amp;gt;&amp;gt; vamp.metadata[&#39;subject&#39;] = &#39;Claire&#39;
=&amp;gt; &quot;Claire&quot;
&amp;gt;&amp;gt; vamp.metadata[&#39;photographer&#39;] = &#39;Nadine Inkster&#39;
=&amp;gt; &quot;Nadine Inkster&quot;
&amp;gt;&amp;gt; vamp.store
=&amp;gt; true
&lt;/pre&gt;
&lt;p&gt;Storing the picture data in a variable&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
&amp;gt;&amp;gt; picdata = vamp.value&lt;br /&gt;
=&amp;gt; &amp;quot;\377\330\377\340\000\020JFIF\000\001\002\000&amp;#8230;&amp;#8230;.&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Downloading a picture by streaming it to an IO object.&lt;/p&gt;
&lt;pre&gt;
&amp;gt;&amp;gt; File.open(&#39;vampire_downloaded.jpg&#39;, &#39;w&#39;) {|file| file.write(vamp.value)}
=&amp;gt; 10817
&amp;gt;&amp;gt; exit
s3demo $&amp;gt;ls
flowers.jpg             vampire.jpg
test.txt                vampire_downloaded.jpg
s3demo $&amp;gt;open vampire_downloaded.jpg 
s3demo $&amp;gt;
&lt;/pre&gt;
&lt;h2&gt;S3Syncer Code&lt;/h2&gt;
&lt;p&gt;Please note that this code is really only useful as an example of how to synchronize with S3.&lt;/p&gt;
&lt;p&gt;It won&amp;#8217;t recurse directories and it dies a horrible death if there are any symlinked files in a directory.&lt;/p&gt;
&lt;p&gt;If you are looking for something to synchronize directories, check out &lt;a href=&quot;http://s3sync.net/wiki&quot;&gt;s3sync.rb&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;digest/md5&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;aws/s3&amp;#39;&lt;/span&gt;
&lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;S3&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;S3Syncer&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:local_files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:files_to_upload&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bucket_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@directory&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@bucket_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bucket_name&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;S3Syncer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;syncer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;S3Syncer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bucket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;syncer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_local_files&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;syncer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect_to_s3&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;syncer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_bucket&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;syncer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select_files_to_upload&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;syncer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sync&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;# This does not recurse directories.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_local_files&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@local_files&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;connect_to_s3&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;establish_connection!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;:access_key_id&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;AMAZON_ACCESS_KEY_ID&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;:secret_access_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;AMAZON_SECRET_ACCESS_KEY&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  
    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ERROR: Connection not made or bad access key &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&amp;quot;or bad secret access key.  Exiting&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;S3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connected?&lt;/span&gt; 
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;  
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_bucket&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Bucket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@bucket_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@bucket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Bucket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@bucket_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;# Files should be uploaded if &lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;#   The file doesn&amp;#39;t exist in the bucket&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;#      OR&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;#   The MD5 hashes don&amp;#39;t match&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;select_files_to_upload&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@files_to_upload&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@local_files&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                 
      &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;directory?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
         &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Don&amp;#39;t upload directories&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@bucket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
         &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Upload if file does not exist on S3&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@bucket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;etag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Digest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MD5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexdigest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
         &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Upload if MD5 sums don&amp;#39;t match&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# the MD5 matches and it exists already, so don&amp;#39;t upload it&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;# This will choke on symlinked files&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sync&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Directories are in sync&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@files_to_upload&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;empty?&lt;/span&gt;

    &lt;span class=&quot;vi&quot;&gt;@files_to_upload&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; ===&amp;gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@bucket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;S3Object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@bucket_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;      
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt; 
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;local_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;__FILE__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;$0&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;S3Syncer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;/Users/Scott/versioned/spattendesign/presentations/s3-on-rails/s3demo&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                &lt;span class=&quot;s1&quot;&gt;&amp;#39;spatten_syncdemo&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h2&gt;S3Syncer demo&lt;/h2&gt;
&lt;p&gt;Start with spatten_syncdemo bucket empty, and four files in the local directory.&lt;/p&gt;
&lt;p&gt;Run the script&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
s3demo $&amp;gt;ls&lt;br /&gt;
flowers.jpg             vampire.jpg&lt;br /&gt;
test.txt                vampire_downloaded.jpg&lt;br /&gt;
s3demo $&amp;gt;s3syncer&lt;br /&gt;
flowers.jpg =&gt; spatten_syncdemo:flowers.jpg
test.txt =&amp;gt; spatten_syncdemo:test.txt&lt;br /&gt;
vampire.jpg =&gt; spatten_syncdemo:vampire.jpg
vampire_downloaded.jpg =&amp;gt; spatten_syncdemo:vampire_downloaded.jpg&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
Run it again, it says there&amp;#8217;s no need to do anything&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
s3demo $&amp;gt;s3syncer&lt;br /&gt;
Directories are in sync&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Change a file locally and sync again&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
s3demo $&amp;gt; vi test.txt&lt;br /&gt;
Make some changes using vi&lt;br /&gt;
s3demo $&amp;gt;s3syncer&lt;br /&gt;
test.txt ===&amp;gt; spatten_syncdemo:test.txt&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Delete flower.jpg using the Firefox S3 Organizer and then sync again.&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
s3demo $&amp;gt;s3syncer&lt;br /&gt;
flowers.jpg ===&amp;gt; spatten_syncdemo:flowers.jpg&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;So there you go, a quick intro to the wonders of Amazon S3.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>synch s3 host plugin update</title>
   <link href="http://scottpatten.ca/2007/12/synch-s3-host-plugin-update.html"/>
   <updated>2007-12-04T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2007/12/synch-s3-host-plugin-update</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve re-written the plugin to use s3sync.rb rather than trying to figure out which files have changed in svn.  It&amp;#8217;s a much better solution, so hopefully those of you who were having trouble will find it works for you now.  Thanks, especially, to Chris in the comments for helping me figure out what was going wrong.&lt;/p&gt;
&lt;p&gt;The plug-in also now has a permanent home in my new Projects section, &lt;a href=&quot;/projects/synching-your-amazon-s3-asset-host-using-capistrano.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Amazon S3, Ruby and Rails talk</title>
   <link href="http://scottpatten.ca/2007/11/amazon-s3-ruby-and-rails-talk.html"/>
   <updated>2007-11-28T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2007/11/amazon-s3-ruby-and-rails-talk</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m going to be giving a talk on Amazon S3, Ruby and Rails at the next &lt;a href=&quot;http://ruby.meetup.com/112/calendar/6693048/&quot;&gt;Vancouver Ruby and Rails meetup&lt;/a&gt;.  It&amp;#8217;s this Monday, December 3rd.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s the talk teaser:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Amazon&amp;#8217;s Simple Storage Service (Amazon S3) is an online storage system. It can be used for backup, serving assets for your Rails application, storing and streaming large media files or storing customer generated assets.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;span class=&quot;caps&quot;&gt;AWS&lt;/span&gt;/S3 gem, written by Marcel Molina, provides an elegant interface to Amazon S3. I&amp;#8217;ll be talking about how S3 works, how to use it in your Ruby scripts and Rails applications and showing off some example code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hope to see you there!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Synching Your Amazon S3 Asset Host using Capistrano</title>
   <link href="http://scottpatten.ca/2007/11/synching-your-amazon-s3-asset-host-using-capistrano.html"/>
   <updated>2007-11-06T00:00:00-08:00</updated>
   <id>http://scottpatten.ca/2007/11/synching-your-amazon-s3-asset-host-using-capistrano</id>
   <content type="html">&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This article is out of date.  The latest version of this article is on the new &lt;a href=&quot;/projects/synching-your-amazon-s3-asset-host-using-capistrano.html&quot;&gt;permanent page in the projects section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So you&amp;#8217;ve got &lt;a href=&quot;/2007/10/setting-up-multiple-asset-hosts-in-rails.html&quot;&gt;multiple asset hosts&lt;/a&gt; running in your Rails application, and you&amp;#8217;re using Amazon&amp;#8217;s S3 to host your assets.  Now you want to make sure that your assets are kept up to date.  This plugin is a Capistrano recipe that keeps the asset hosts synchronized with the public directory in your subversion repository.&lt;/p&gt;
&lt;h3&gt;Usage&lt;/h3&gt;
&lt;p&gt;After you get everything setup and do your first deploy, just run &lt;code&gt;cap deploy&lt;/code&gt; as normal and all changed files in &lt;code&gt;RAILS_ROOT/public&lt;/code&gt; will be uploaded to all of your asset host buckets before the final &lt;code&gt;deploy:symlink&lt;/code&gt; task.&lt;/p&gt;
&lt;p&gt;The following tasks are also available:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;cap s3_asset_host:get_s3_revision&lt;/li&gt;
	&lt;li&gt;cap s3_asset_host:find_changed&lt;/li&gt;
	&lt;li&gt;cap s3_asset_host:list_changed&lt;/li&gt;
	&lt;li&gt;cap s3_asset_host:find_all&lt;/li&gt;
	&lt;li&gt;cap s3_asset_host:upload_changed&lt;/li&gt;
	&lt;li&gt;cap s3_asset_host:upload_all&lt;/li&gt;
	&lt;li&gt;cap s3_asset_host:upload&lt;/li&gt;
	&lt;li&gt;cap s3_asset_host:reset_and_upload&lt;/li&gt;
	&lt;li&gt;cap s3_asset_host:setup&lt;/li&gt;
	&lt;li&gt;cap s3_asset_host:create_buckets&lt;/li&gt;
	&lt;li&gt;cap s3_asset_host:delete_all&lt;/li&gt;
	&lt;li&gt;cap s3_asset_host:connect&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can get documentation on these tasks by running &lt;code&gt;cap -T&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Requirements&lt;/h3&gt;
&lt;p&gt;This plug-in is a Capistrano extension.  It requires Capistrano 2.0.0 or greater.&lt;/p&gt;
&lt;p&gt;You will also require the &lt;a href=&quot;http://amazon.rubyforge.org&quot;&gt;aws-s3 gem&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So far, this plug-in:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;assumes that you are using the &amp;#8216;checkout&amp;#8217; method of deployment.&lt;/li&gt;
	&lt;li&gt;only works with svn.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are using another version control system, I think all you&amp;#8217;ll have to change is the two methods in lib/scm.rb.  If you do get something other than svn working, please &lt;a href=&quot;mailto:scott@scottpatten.ca&quot;&gt;let me know&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to use more than one asset host, then you have to either install the multiple asset hosts plugin &lt;br /&gt;
or upgrade to Rails 2.0 (see &lt;a href=&quot;/2007/10/setting-up-multiple-asset-hosts-in-rails.html&quot;&gt;setting up multiple asset hosts in Rails&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;Setup&lt;/h3&gt;
&lt;p&gt;To set-up, you need to do the following&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Install the plug-in&lt;/li&gt;
	&lt;li&gt;Install the &lt;span class=&quot;caps&quot;&gt;AWS&lt;/span&gt;-S3 gem.&lt;/li&gt;
	&lt;li&gt;Set up your Rails application to use asset hosts.&lt;/li&gt;
	&lt;li&gt;Set up your asset hosts.&lt;/li&gt;
	&lt;li&gt;Configure Capistrano.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Installing the plug-in&lt;/h4&gt;
&lt;p&gt;From &lt;code&gt;RAILS_ROOT&lt;/code&gt;, run:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;script/plugin install svn://svn.spattendesign.com/svn/plugins/synch_s3_asset_host&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;Installing the &lt;span class=&quot;caps&quot;&gt;AWS&lt;/span&gt;-S3 gem&lt;/h4&gt;
&lt;p&gt;You need to do this on both your local computer &lt;strong&gt;and&lt;/strong&gt; the computer that is defined as the asset_host_syncher (see Capistrano Configuration, below).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$&amp;gt; sudo gem install aws-s3&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;Setting up your Rails app to use asset hosts&lt;/h4&gt;
&lt;h5&gt;Single asset host&lt;/h5&gt;
&lt;p&gt;For a single asset host, simply add the following line to &lt;code&gt;RAILS_ROOT/config/environments/production.rb&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;config.action_controller.asset_host = &quot;http://assets.example.com&quot;&lt;/code&gt;&lt;/p&gt;
&lt;h5&gt;Multiple asset hosts&lt;/h5&gt;
&lt;p&gt;Follow the instructions in &lt;a href=&quot;/2007/10/setting-up-multiple-asset-hosts-in-rails.html&quot;&gt;setting up multiple asset hosts in Rails&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Setting up your asset hosts&lt;/h4&gt;
&lt;p&gt;Set up a &lt;span class=&quot;caps&quot;&gt;CNAME&lt;/span&gt; entry for each asset host pointing to &lt;code&gt;s3.amazonaws.com&lt;/code&gt;.  How you do this depends on your domain host.  Here&amp;#8217;s what it looks like on &lt;a href=&quot;http://easydns.com&quot;&gt;easydns&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/easydns_cname.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You may need to wait up to 24 hours for the &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt; entries for these new hosts to propagate.&lt;/p&gt;
&lt;h4&gt;Configuring Capistrano&lt;/h4&gt;
&lt;h5&gt;Capistrano installation&lt;/h5&gt;
&lt;p&gt;This plugin requires Capistrano 2.0.0 or greater.&lt;/p&gt;
&lt;p&gt;To upgrade to the latest version (currently 2.1.0):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$&amp;gt; gem install capistrano&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Once the plug-in is installed, make sure that the recipes are seen by Capistrano&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$&amp;gt; cap -T | grep s3_asset_host&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;should return a bunch of tasks.  If you don&amp;#8217;t see anything listed, then you need to update your &lt;code&gt;Capfile&lt;/code&gt; by doing the following (this is &lt;a href=&quot;http://groups.google.com/group/capistrano/browse_thread/thread/531ad32aff5fe5a8&quot;&gt;from Jamis Buck&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;In Capistrano 2.1.0 or above:&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
$&amp;gt; cd RAILS_ROOT&lt;br /&gt;
$&amp;gt; rm Capfile&lt;br /&gt;
$&amp;gt; capify .&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;If you do not want to delete your &lt;code&gt;Capify&lt;/code&gt; file, or if you are using Capistrano 2.0.0, add the following line to your &lt;code&gt;Capify&lt;/code&gt; file:&lt;br/&gt;
&lt;code&gt;Dir[&#39;vendor/plugins/*/recipes/*.rb&#39;].each { |plugin| load(plugin) }&lt;/code&gt;&lt;/p&gt;
&lt;h5&gt;Capistrano configuration&lt;/h5&gt;
&lt;p&gt;Create a new file in &lt;code&gt;RAILS_ROOT/config&lt;/code&gt; called &lt;code&gt;synch_s3_asset_host.rb&lt;/code&gt;.  Add the following lines to it, and edit to suit:&lt;/p&gt;
&lt;pre&gt;
# =============================================================================
# S3 ASSET HOST OPTIONS
# =============================================================================
set :asset_host_name, &quot;assets%d.example.com&quot;
set :aws_access_key, &quot;your Amazon AWS access key&quot; # You can also set this in your environment as AMAZON_ACCESS_KEY_ID
set :amazon_secret_access_key, &quot;your Amazon AWS secret&quot; # You can also set this in your environment as AMAZON_SECRET_ACCESS_KEY
# set :dry_run, false# Set to true if you want to test the asset_host uploading without doing anything on Amazon S3
before &quot;deploy:symlink&quot;, &quot;s3_asset_host:upload_changed&quot;
&lt;/pre&gt;
&lt;p&gt;You have to do one more thing: in &lt;code&gt;RAILS_ROOT/config/deploy.rb&lt;/code&gt;.  Specify one of your web hosts as an &amp;#8220;asset_host_syncher&amp;#8221;, like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;role :web, webserver1, :asset_host_syncher =&amp;gt; true&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;The first deploy&lt;/h4&gt;
&lt;p&gt;Commit all changes to your rails application and do the initial bucket setup:&lt;/p&gt;
&lt;pre&gt;
$&amp;gt; cap s3_asset_host:setup
$&amp;gt; svn commit -m &quot;Adding synch_s3_asset_host plugin&quot;
$&amp;gt; cap deploy
&lt;/pre&gt;
&lt;p&gt;This will do the following:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Create your Amazon S3 &lt;span class=&quot;caps&quot;&gt;AWS&lt;/span&gt; buckets&lt;/li&gt;
	&lt;li&gt;upload everything in RAILS_ROOT/public (in your svn repository) to each bucket&lt;/li&gt;
	&lt;li&gt;Set the revision in each bucket to the latest revision in your repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This could take a while if you have lots of images or other big files.&lt;/p&gt;
&lt;h3&gt;You&amp;#8217;re done!&lt;/h3&gt;
&lt;p&gt;That should do it.  Now, every time you run &lt;code&gt;cap deploy&lt;/code&gt;, your asset hosts should be updated with any changes to files in &lt;code&gt;RAILS_ROOT/public&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let me know if you have any problems, suggestions or comments.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Serving local files while using an asset host</title>
   <link href="http://scottpatten.ca/2007/10/serving-local-files-while-using-an-asset-host.html"/>
   <updated>2007-10-25T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2007/10/serving-local-files-while-using-an-asset-host</id>
   <content type="html">&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;NOTE&lt;/span&gt;:  The svn repository referenced here is no longer running.  Hopefully you&amp;#8217;re running an new enough version of Rails that this post isn&amp;#8217;t necessary.&lt;/p&gt;
&lt;p&gt;So, you&amp;#8217;ve &lt;a href=&quot;/2007/10/setting-up-multiple-asset-hosts-in-rails.html&quot;&gt;set up an asset host&lt;/a&gt; for your Rails application, but you have some files that that you don&amp;#8217;t want to or can&amp;#8217;t put on your asset host.&lt;/p&gt;
&lt;p&gt;As an example, &lt;a href=&quot;http://www.plotomatic.com&quot;&gt;Plot-O-Matic&lt;/a&gt; creates images (of graphs) on the fly.  If I had just blithely switched over to using asset hosting, then you wouldn&amp;#8217;t see any changes when you updated a graph on Plot-O-Matic, as the Rails application only updates the graph image in its local public directory, and the asset host file remains unchanged.&lt;/p&gt;
&lt;p&gt;You have a few options to fix this.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;You could, of course, just use straight &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; tags to get at your local files, but that&amp;#8217;s &lt;del&gt;kind of&lt;/del&gt; just plain ugly.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;You could just create the files in a directory that&amp;#8217;s not in public.  But then you can&amp;#8217;t let people link to them easily, and you&amp;#8217;re still not able to use asset tag helpers.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Finally, you could create a asset tag helper that created local links.  That&amp;#8217;s what I chose to do on Plot-O-Matic, and here&amp;#8217;s how I did it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Getting started&lt;/h3&gt;
&lt;p&gt;This will only work with the latest changes to the asset host code.  There are two ways you can get this.&lt;/p&gt;
&lt;h6&gt;Upgrade to Rails 2.0&lt;/h6&gt;
&lt;p&gt;For instructions, scroll to the bottom of &lt;a href=&quot;http://weblog.rubyonrails.org/2007/9/30/rails-2-0-0-preview-release&quot;&gt;this post&lt;/a&gt;.&lt;/p&gt;
&lt;h6&gt;Install the multiple_asset_hosts plugin&lt;/h6&gt;
&lt;pre&gt;script/plugin install svn://svn.spattendesign.com/svn/plugins/multiple_asset_hosts&lt;/pre&gt;
&lt;p&gt;All this plugin does is monkeypatch in the multiple asset host functionality from Rails Edge.&lt;/p&gt;
&lt;h3&gt;Creating the helper&lt;/h3&gt;
&lt;p&gt;Let&amp;#8217;s take a look at how the standard image tag helper works.  The&lt;br /&gt;
following code is from&lt;br /&gt;
&lt;code&gt;vendor/rails/actionpack/lib/action_view/helpers/asset_tag_helper.rb&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;image_tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;symbolize_keys!&lt;/span&gt;
            
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:alt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;.*&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;capitalize&lt;/span&gt;
       
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:height&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;%r{^\d+x\d+$}&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;The important part here is the line&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;This is where the path is calculated.  Let&amp;#8217;s take a closer look at the &lt;code&gt;image_path&lt;/code&gt; method&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;image_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blank?&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;ActiveSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Deprecation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;You&amp;#39;ve called image_path with a source that doesn&amp;#39;t include an extension. &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;In Rails 2.0, that will not result in .png automatically being appended. &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;So you should call image_path(&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.png&amp;#39;) instead&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;caller&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;compute_public_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;images&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;png&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;OK, so all that that does is call &lt;code&gt;compute_public_path&lt;/code&gt;.  &lt;code&gt;compute_public_path&lt;/code&gt; is the part that has been updated to work with multiple asset hosts:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compute_public_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;.&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ext&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blank?&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;%r{^[-a-z]+://}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?/&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@controller&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;relative_url_root&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;rewrite_asset_path!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_host&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compute_asset_host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blank?&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;%r{^[-a-z]+://}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@controller&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

      &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Aha!  So, all we need to do to get local calls is make a call to &lt;code&gt;compute_public_path&lt;/code&gt; with &lt;code&gt;include_host = false&lt;/code&gt;.  Let&amp;#8217;s create a &lt;code&gt;local_image_tag&lt;/code&gt; helper that does just that.  The following code should reside in &lt;code&gt;RAILS_ROOT/app/helpers/application_helper.rb&lt;/code&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#Creates an image tag for a file on the server, ignoring any asset hosts.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#Other than that, this is equivalent and mostly stolen from asset_tag_helper#image_tag&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;local_image_tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;symbolize_keys!&lt;/span&gt;
          
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_image_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:alt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;.*&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;capitalize&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:height&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;%r{^\d+x\d+$}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;img&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Returns the path to an image on the server, ignoring any asset hosts.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Other than that, this is equivalent to asset_tag_helper#image_path&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;local_image_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blank?&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;ActiveSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Deprecation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;You&amp;#39;ve called image_path with a source that doesn&amp;#39;t include an extension. &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;In Rails 2.0, that will not result in .png automatically being appended. &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&amp;quot;So you should call image_path(&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.png&amp;#39;) instead&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;caller&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;compute_public_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;images&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;png&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;This is too ugly.  What we really want is to be able to create an image tag like this:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;local_image_tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;image_tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:include_host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;to do this, you would change the image_tag code to something like this&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;image_tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;symbolize_keys!&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;include_host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;has_key?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:include_host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:include_host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:include_host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:alt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;.*&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;capitalize&lt;/span&gt;

  
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:height&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;x&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;%r{^\d+x\d+$}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;img&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;and the &lt;code&gt;image_path&lt;/code&gt; code to&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;image_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blank?&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;ActiveSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Deprecation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;warn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;You&amp;#39;ve called image_path with a source that doesn&amp;#39;t include an extension. &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;In Rails 2.0, that will not result in .png automatically being appended. &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&amp;quot;So you should call image_path(&amp;#39;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.png&amp;#39;) instead&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;caller&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;compute_public_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;images&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;png&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;include_host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;</content>
 </entry>
 
 <entry>
   <title>Setting up multiple asset hosts in Rails</title>
   <link href="http://scottpatten.ca/2007/10/setting-up-multiple-asset-hosts-in-rails.html"/>
   <updated>2007-10-24T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2007/10/setting-up-multiple-asset-hosts-in-rails</id>
   <content type="html">&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;NOTE&lt;/span&gt;:  The svn repository referenced here is no longer running.  Hopefully you&amp;#8217;re running an new enough version of Rails that this post isn&amp;#8217;t necessary.&lt;/p&gt;
&lt;p&gt;One of the &lt;a href=&quot;http://www.chadfowler.com/2007/2/18/edge-rails-goody-distributed-asset-hosts&quot;&gt;nice goodies&lt;/a&gt; coming in Rails 2.0 is the ability to use &lt;a href=&quot;http://dev.rubyonrails.org/changeset/6161&quot;&gt;multiple asset hosts&lt;/a&gt;.  This article explains how you can use this feature now, without waiting for Rails 2.0, and why you would want to use asset hosts.&lt;/p&gt;
&lt;h3&gt;What&amp;#8217;s an asset host, and why would I want to use it?&lt;/h3&gt;
&lt;p&gt;An asset host is another server, somewhere on the internet, where you store your static files.  These can be javascripts scripts, &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; stylesheets, images, static html files and anything else that doesn&amp;#8217;t change often.  Basically, anything that lives in your public directory.  You can then use a link to the asset host whenever you want to  include an image, javascript or stylesheet.  For example, &lt;a href=&quot;http://www.plotomatic.com&quot;&gt;Plot-O-Matic&lt;/a&gt; stores its assets at assets0.plotomatic.com  &amp;#8212;  assets3.plotomatic.com.  You can see the logo here: &lt;a href=&quot;http://assets0.plotomatic.com/images/o-logo.png&quot;&gt;assets0.plotomatic.com/images/o-logo.png&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So, why would you want to use an asset host?  It &lt;a href=&quot;http://www.die.net/musings/page_load_time/&quot;&gt;turns out&lt;/a&gt; that many browsers limit the number of simultaneous connections to a host.  For Internet Explorer, that number is &lt;strong&gt;two&lt;/strong&gt;.  If you are serving a lot of small images, or you haven&amp;#8217;t bothered to bundle your scripts or stylesheets, this can be a real bottleneck.  Asset hosting allows you to increase the number of hosts a web page is loaded from, removing the bottleneck.&lt;/p&gt;
&lt;h3&gt;Asset hosting in Rails&lt;/h3&gt;
&lt;p&gt;Rails has had support for using a single asset host for &lt;a href=&quot;http://casey0.com/archive/2006/October/How_to_serve_the_rails_public_directory_out_of_S3.html&quot;&gt;at least a year&lt;/a&gt;.  It&amp;#8217;s achieved by setting &lt;code&gt;config.action_controller.asset_host&lt;/code&gt; in your development environment, &lt;code&gt;development.rb&lt;/code&gt;.  For example,&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action_controller&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asset_host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://assets.plotomatic.com&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Once you do this, rails will pre-pend every link created with an &lt;a href=&quot;http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html&quot;&gt;asset tag helper&lt;/a&gt; with your asset host name.  So, a link like this&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image_tag&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;o-logo.png&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;will now result in the following link&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;o-logo&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;http://assets.plotomatic.com/images/o-logo.png?1193172652&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Asset tag helpers are things like &lt;code&gt;image_tag&lt;/code&gt;, &lt;code&gt;stylesheet_link_tag&lt;/code&gt; or &lt;code&gt;javascript_include_tag&lt;/code&gt;.  Links made without asset tag helpers will not automatically use your asset host.&lt;/p&gt;
&lt;h3&gt;Multiple asset hosts&lt;/h3&gt;
&lt;p&gt;Now, having a single asset host is nice, but using multiple asset hosts can really speed up those page load times.  Here&amp;#8217;s how you do it:&lt;/p&gt;
&lt;h4&gt;Get Rails ready for multiple asset hosts&lt;/h4&gt;
&lt;p&gt;There are two ways you can do this.&lt;/p&gt;
&lt;h6&gt;Upgrade to Rails 2.0&lt;/h6&gt;
&lt;p&gt;For instructions, scroll to the bottom of &lt;a href=&quot;http://weblog.rubyonrails.org/2007/9/30/rails-2-0-0-preview-release&quot;&gt;this post&lt;/a&gt;.&lt;/p&gt;
&lt;h6&gt;Install the multiple_asset_hosts plugin&lt;/h6&gt;
&lt;p&gt;&lt;code&gt;script/plugin install svn://svn.spattendesign.com/svn/plugins/multiple_asset_hosts&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;All this plugin does is monkeypatch in the multiple asset host functionality from Rails Edge.&lt;/p&gt;
&lt;h4&gt;Pick a name for your asset hosts&lt;/h4&gt;
&lt;p&gt;The change from single to multiple asset hosts is simple.  You simply put a &lt;code&gt;%d&lt;/code&gt; somewhere in your asset host name in &lt;code&gt;production.rb&lt;/code&gt;.  For Plot-O-Matic, the setting is&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;action_controller&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asset_host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://assets%d.plotomatic.com&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;Rails will replace the &lt;code&gt;%d&lt;/code&gt; with either 0, 1, 2 or 3.&lt;/p&gt;
&lt;h4&gt;Set up your asset hosts&lt;/h4&gt;
&lt;p&gt;You need to provide four asset hosts, so I set up four asset hosts named&lt;br /&gt;
 &lt;code&gt;assets0.plotomatic.com&lt;/code&gt;, &lt;code&gt;assets1.plotomatic.com&lt;/code&gt;, &lt;code&gt;assets2.plotomatic.com&lt;/code&gt; and &lt;code&gt;assets3.plotomatic.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I used Amazon S3 for my asset hosts, which was simple:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;set up four buckets called &lt;code&gt;assets0.plotomatic.com&lt;/code&gt;, &lt;code&gt;assets1.plotomatic.com&lt;/code&gt;, &lt;code&gt;assets2.plotomatic.com&lt;/code&gt; and &lt;code&gt;assets3.plotomatic.com&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Set up a &lt;span class=&quot;caps&quot;&gt;CNAME&lt;/span&gt; entry for each asset host pointing to &lt;code&gt;s3.amazonaws.com&lt;/code&gt;.  How you do this depends on your domain host.  Here&amp;#8217;s what it looks like on &lt;a href=&quot;http://easydns.com&quot;&gt;easydns&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/images/easydns_cname.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;Deploy it&lt;/h4&gt;
&lt;ul&gt;
	&lt;li&gt;Commit your changes to your version control system&lt;/li&gt;
	&lt;li&gt;Upload everything in your public directory to each of your asset hosts.&lt;/li&gt;
	&lt;li&gt;Deploy and restart your web server&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>running tests on deploy</title>
   <link href="http://scottpatten.ca/2007/10/running-tests-on-deploy.html"/>
   <updated>2007-10-19T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2007/10/running-tests-on-deploy</id>
   <content type="html">&lt;p&gt;A simple Capistrano 2.0 recipe, installable as a plugin, that runs all of your tests before the final symlink test.&lt;/p&gt;
&lt;h3&gt;Synopsis&lt;/h3&gt;
&lt;p&gt;This plug-in is a Capistrano extension.  It requires Capistrano 2.0.0 or greater.&lt;/p&gt;
&lt;p&gt;Once installed, running &lt;code&gt;cap deploy&lt;/code&gt; will run all of your tests before doing the final symlink.&lt;/p&gt;
&lt;p&gt;If the tests fail, the symlink will not be created and your deployment will roll back.&lt;/p&gt;
&lt;p&gt;to deploy without tests,&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cap deploy:without_tests&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;h4&gt;Plugin installation&lt;/h4&gt;
&lt;p&gt;You should be able to install with the following command (from rails root):&lt;/p&gt;
&lt;p&gt;Rails 3:&lt;br /&gt;
&lt;code&gt;rails plugin install
http://github.com/spatten/Run-Tests-on-Deploy.git&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Rails 2:&lt;br /&gt;
&lt;code&gt;script/plugin install http://github.com/spatten/Run-Tests-on-Deploy.git&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If that doesn&amp;#8217;t work, send me an e-mail at &lt;a href=&quot;mailto:scott@scottpatten.ca&quot;&gt;scott@scottpatten.ca&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Capistrano configuration&lt;/h4&gt;
&lt;p&gt;This plugin requires Capistrano 2.0.0 or greater.&lt;br /&gt;
To upgrade to the latest version (currently 2.1.0)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gem install capistrano&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Once the plug-in is installed, make sure that the recipes are seen by Capistrano&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cap -T | grep deploy:without_tests&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;should return&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cap deploy:without_tests          # deploy without running tests&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If capistrano is not seeing the &lt;code&gt;deploy:without_tests&lt;/code&gt; task, then you need to update your Capfile.&lt;/p&gt;
&lt;p&gt;(The following is from &lt;a href=&quot;http://groups.google.com/group/capistrano/browse_thread/thread/531ad32aff5fe5a8&quot;&gt;a post by Jamis Buck&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;In Capistrano 2.1.0 or above:&lt;br /&gt;
you can delete your Capify file in rails root, and then, from rails root, run&lt;/p&gt;
&lt;p&gt;&lt;code&gt;capify .&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you do not want to delete your Capify file, or if you are using Capistrano 2.0.0, add the following line to your Capify file:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;vendor/plugins/*/recipes/*.rb&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plugin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plugin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3&gt;Details&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;deploy:run_tests&lt;/code&gt; task is executed before the &lt;code&gt;symlink&lt;/code&gt;&lt;br /&gt;
task.  The &lt;code&gt;run_tests&lt;/code&gt; task does the following:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;prepares your test db with &lt;code&gt;rake db:test:prepare&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;runs all of your tests with &lt;code&gt;rake test&lt;/code&gt; at a nice level of -10&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;deploy:run_tests&lt;/code&gt; task won&amp;#8217;t work if you call it by itself, as it runs from the&lt;br /&gt;
release_path directory, which won&amp;#8217;t exist unless called after &lt;code&gt;deploy:update_code&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;to deploy without tests, &lt;code&gt;cap deploy:without_tests&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;you can also set the run_tests option to 0 from the command line like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cap -S run_tests=0 deploy&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;this allows you to do things like deploying with migrations but without tests:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cap -S run_tests=0 deploy:migrations&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Genesis&lt;/h3&gt;
&lt;p&gt;The original idea for the &lt;code&gt;:run_tests&lt;/code&gt; task is from the &lt;a href=&quot;http://blog.testingrails.com/2006/9/4/running-tests-on-deploy-with-capistrano&quot;&gt;testing rails blog&lt;/a&gt;,&lt;br /&gt;
which, sadly, seems to be defunct.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>updating rdig on deploy</title>
   <link href="http://scottpatten.ca/2007/10/updating-rdig-on-deploy.html"/>
   <updated>2007-10-16T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2007/10/updating-rdig-on-deploy</id>
   <content type="html">&lt;p&gt;Here&amp;#8217;s a simple little Capistrano 2.0 recipe to update your &lt;a href=&quot;http://rdig.rubyforge.org/&quot;&gt;rdig&lt;/a&gt; search index after every deploy.&lt;/p&gt;
&lt;p&gt;Add the following lines to &lt;code&gt;config/deploy.rb&lt;/code&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:deploy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;after&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:deploy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;deploy:update_rdig&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Update the rdig database.  This has to be done after&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;        re-starting,  as it looks at the live web-site&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:update_rdig&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;cd &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_path&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &amp;amp;&amp;amp; rdig -c config/rdig_config.rb&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;This will run automatically after every deploy.  If you just want to run it manually, comment out the line that starts with &lt;code&gt;after ...&lt;/code&gt;.&lt;br /&gt;
You can then run it manually with &lt;code&gt;cap deploy:update_rdig&lt;/code&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Ruby unit test command line options</title>
   <link href="http://scottpatten.ca/2007/10/ruby-unit-test-command-line-options.html"/>
   <updated>2007-10-11T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2007/10/ruby-unit-test-command-line-options</id>
   <content type="html">&lt;p&gt;Here are a few tips and tricks for unit tests&lt;/p&gt;
&lt;p&gt;To find all of the command line options for the test::unit suite, call a unit test with &lt;code&gt;--help&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ruby some_test.rb --help&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The output will look something like this&lt;/p&gt;
&lt;pre&gt;
~/tests $&amp;gt;ruby some_test.rb --help
Test::Unit automatic runner.
Usage: test/unit/graph_test.rb [options] [-- untouched arguments]

    -r, --runner=RUNNER              Use the given RUNNER.
                                     (c[onsole], f[ox], g[tk], g[tk]2, t[k])
    -n, --name=NAME                  Runs tests matching NAME.
                                     (patterns may be used).
    -t, --testcase=TESTCASE          Runs tests in TestCases matching TESTCASE.
                                     (patterns may be used).
    -v, --verbose=[LEVEL]            Set the output level (default is verbose).
                                     (s[ilent], p[rogress], n[ormal], v[erbose])        --                           Stop processing options so that the
                                     remaining options will be passed to the
                                     test.
    -h, --help                       Display this help.

Deprecated options:
        --console                    Console runner (use --runner).
        --gtk                        GTK runner (use --runner).
        --fox                        Fox runner (use --runner).
&lt;/pre&gt;
&lt;h3&gt;Running only some tests&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;-n&lt;/code&gt; option is my favourite.  You can use it like this to call a single test by giving it the name of a test method:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ruby some_test.rb -n test_something_very_important&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Even better, you can use a regular expression and all of the matching tests will be run.  For example, if I had a graph model that tested the creation of .png, .eps and .gif files with methods called &lt;code&gt;test_create_png_file&lt;/code&gt;, &lt;code&gt;test_create_eps_file&lt;/code&gt; and &lt;code&gt;test_create_gif_file&lt;/code&gt;, I could run them all with the command&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ruby test/unit/graph_test.rb -n /_create_.*_file/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;you can also use the &lt;code&gt;-n&lt;/code&gt; option multiple times.  So, if I just wanted to test eps and png file creation, I could use&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ruby test/unit/graph_test.rb -n test_create_eps_file -n test_create_png_file&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The same thing applies to selecting test cases using the &lt;code&gt;-t&lt;/code&gt; option.&lt;/p&gt;
&lt;h3&gt;Cranking up the verbosity&lt;/h3&gt;
&lt;p&gt;Sometimes you want to see what tests are failing without waiting for all of the tests to run.  Use the &lt;code&gt;-v&lt;/code&gt; or &lt;code&gt;--verbose&lt;/code&gt; options to do this.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ruby test/unit/&amp;lt;some_test&amp;gt;_test.rb -v v&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ruby test/unit/&amp;lt;some_test&amp;gt;_test.rb --verbose=verbose&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Then, instead of just the boring old periods appearing as each test passes&lt;/p&gt;
&lt;pre&gt;
~/rails/grapher/trunk/vendor/plugins/ploticus $&amp;gt;ruby test/ploticus_test.rb 
Loaded suite test/ploticus_test
Started
.................
Finished in 0.10768 seconds.

17 tests, 118 assertions, 0 failures, 0 errors
&lt;/pre&gt;
&lt;p&gt;you&amp;#8217;ll see this instead:&lt;/p&gt;
&lt;pre&gt;
~/rails/grapher/trunk/vendor/plugins/ploticus $&amp;gt;ruby test/ploticus_test.rb -v v
Loaded suite test/ploticus_test
Started
test_data_from_columns(PloticusTest): .
test_data_from_columns_with_ragged_data(PloticusTest): .
test_data_from_hash(PloticusTest): .
test_data_from_hash_with_nils(PloticusTest): .
test_data_from_hash_with_ragged_data(PloticusTest): .
test_data_from_rows(PloticusTest): .
test_first_proc_by_name(PloticusTest): .
test_has_proc(PloticusTest): .
test_num_procs_by_name(PloticusTest): .
test_pad_to(PloticusTest): .
test_ploticus_proc_has_line(PloticusTest): .
test_ploticus_proc_line(PloticusTest): .
test_png_graph_creation(PloticusTest): .
test_proc_with_colons_in_it(PloticusTest): .
test_procs_are_enumerable(PloticusTest): .
test_procs_by_name(PloticusTest): .
test_svg_graph_creation(PloticusTest): .

Finished in 0.042398 seconds.

17 tests, 118 assertions, 0 failures, 0 errors
&lt;/pre&gt;
&lt;p&gt;Obviously you don&amp;#8217;t want to do this all of the time, but it can come in handy.&lt;/p&gt;
&lt;h3&gt;Running tests with a &lt;span class=&quot;caps&quot;&gt;GUI&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;If you get bored with the command line, try using the &amp;#8220;runner&amp;#8221; option.  The tk option worked for me without having to install anything:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ruby some_test.rb -r tk&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You&amp;#8217;ll see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/tk_unit_test_runner.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Other valid options are console, fox, gtk, gtk2, tk.&lt;/p&gt;
&lt;p&gt;You can mix the &lt;code&gt;-n&lt;/code&gt; and &lt;code&gt;-t&lt;/code&gt; options as well if you want&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ruby test/unit/graph_test.rb -r t -n /downloadable/&lt;/code&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Updating dynamic DNS on Amazon EC2</title>
   <link href="http://scottpatten.ca/2007/10/updating-dynamic-dns-on-amazon-ec2.html"/>
   <updated>2007-10-10T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2007/10/updating-dynamic-dns-on-amazon-ec2</id>
   <content type="html">&lt;h3&gt;basic idea&lt;/h3&gt;
&lt;p&gt;There are two steps to updating your dynamic &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt;.&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Get your IP address&lt;/li&gt;
	&lt;li&gt;Tell your dynamic &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt; provider the IP address&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On EC2, things are a little different from your standard hosting setup.  Here&amp;#8217;s how you get dynamic &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt; working on EC2.&lt;/p&gt;
&lt;h3&gt;Getting your IP address&lt;/h3&gt;
&lt;p&gt;See this Amazon article about &lt;a href=&quot;http://docs.amazonwebservices.com/AWSEC2/2007-03-01/DeveloperGuide/AESDG-chapter-instancedata.html&quot;&gt;getting data about your instance&lt;/a&gt; for more information about instance data.&lt;/p&gt;
&lt;p&gt;To make a &lt;strong&gt;long&lt;/strong&gt; story short, to find out the public IP address of your EC2 instance, you make a http get request to&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://169.254.169.254/latest/meta-data/public-ipv4&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Note that this has to be done from your EC2 instance.&lt;/p&gt;
&lt;p&gt;Try it out from the command line.  Log-in to your EC2 instance and type&lt;/p&gt;
&lt;p&gt;&lt;code&gt;curl http://169.254.169.254/latest/meta-data/public-ipv4&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;From Ruby, it&amp;#8217;s just as simple.  Cut and paste this into a script, or just run it in &lt;code&gt;irb&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;open-uri&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;http://169.254.169.254/latest/meta-data/public-ipv4&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;h3&gt;Updating your &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt; with your dynamic &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt; provider&lt;/h3&gt;
&lt;p&gt;The following instructions assume that you want to use &lt;a href=&quot;http://ez-ipupdate.com/&quot;&gt;ez-ipupdate&lt;/a&gt; to update your &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt;.  If you don&amp;#8217;t want to, or if ez-ipupdate doesn&amp;#8217;t support your dynamic &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt; provider, it should be relatively simple to get it working anyways.&lt;/p&gt;
&lt;p&gt;For example, &lt;a href=&quot;http://easydns.com&quot;&gt;easy-dns&lt;/a&gt; (who I use) just requires logging in and then sending a get request &lt;a href=&quot;http://support.easydns.com/tutorials/dynamicUpdateSpecs.php&quot;&gt;formatted like this&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;
http://members.easydns.com/dyn/dyndns.php?hostname=example.com&amp;amp;myip=10.0.0.2
&lt;/pre&gt;
&lt;h4&gt;Installing ez-ipupdate&lt;/h4&gt;
&lt;p&gt;If you&amp;#8217;re running Ubuntu, then install it using &lt;code&gt;sudo aptitude install ez-ipupdate&lt;/code&gt; or &lt;code&gt;sudo apt-get install ez-ipupdate&lt;/code&gt;.  On a RedHat installation &lt;code&gt;sudo yum install ez-ipupdate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can also &lt;a href=&quot;http://ez-ipupdate.com/&quot;&gt;install from source&lt;/a&gt;, of course.&lt;/p&gt;
&lt;p&gt;When you install it using &lt;code&gt;aptitude&lt;/code&gt; or &lt;code&gt;apt-get&lt;/code&gt;, it will ask you for some configuration info.  This won&amp;#8217;t work on EC2, so ignore the configuration and use the script below instead.&lt;/p&gt;
&lt;h4&gt;Installing the Ruby script&lt;/h4&gt;
&lt;p&gt;Here&amp;#8217;s the script:&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;open-uri&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;yaml&amp;#39;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;DYNAMIC_DNS_CONFIG_FILE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;/etc/ez-ipupdate/dynamic_dns.yml&amp;#39;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;AMAZON_INSTANCE_DATA_ADDRESS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://169.254.169.254&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;api&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;latest&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;AMAZON_INSTANCE_DATA_ADDRESS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;meta-data&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;public-ipv4&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;dns_config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;DYNAMIC_DNS_CONFIG_FILE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hosts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dns_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;host&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;updating dynamic dns to ip = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; for host &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; using dynamic DNS service &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
       &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dns_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;service&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ez-ipupdate --address &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; --service-type &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dns_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;service&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&amp;quot;--user &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dns_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;username&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dns_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;password&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; --host &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;If you&amp;#8217;re running an &lt;a href=&quot;http://ec2onrails.rubyforge.org/&quot;&gt;ec2-on-rails&lt;/a&gt; instance, place the script in &lt;code&gt;/usr/local/ec2-on-rails/startup-scripts/every-startup/update_dynamic_dns.rb&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Otherwise, place it somewhere in your path and create a shell script to call it in &lt;code&gt;/etc/init.d&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Make sure that both update_dynamic_dns.rb and the init script are executable.&lt;/p&gt;
&lt;h4&gt;The config file&lt;/h4&gt;
&lt;p&gt;Create a file called &lt;code&gt;/etc/ez-ipupdate/dynamic_dns.yml&lt;/code&gt;.  It should look something like this&lt;/p&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# service should be one of the services supported by ez-ipupdate. &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Possible values: null  ezip  pgpow  dhs  dyndns  dyndns-static &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#                         dyndns-custom ods tzo easydns easydns-partner &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#                         gnudip justlinux dyns hn zoneedit heipv6tb&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# (The above list is from man ez-ipupdate)&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service_type&lt;/span&gt; 
&lt;span class=&quot;ss&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username_for_your_dynamic_dns_provider&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password_for_your_dynamic_dns_provider&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;example1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;example2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;p&gt;To update multiple hosts, put them all on the host entry, separated by commas.&lt;/p&gt;
&lt;h4&gt;Testing and debugging&lt;/h4&gt;
&lt;p&gt;Test out the script:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;run it: &lt;code&gt;./update_dynamic_dns.rb&lt;/code&gt;.&lt;/li&gt;
	&lt;li&gt;Wait a couple of minutes.&lt;/li&gt;
	&lt;li&gt;ping your domain name from a local machine and make sure that it points at the right IP address.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hopefully that works for you.  Let me know if you have any problems, comments or suggestions.&lt;/p&gt;
&lt;p&gt;Scott&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Welcome</title>
   <link href="http://scottpatten.ca/2007/10/first-post.html"/>
   <updated>2007-10-09T00:00:00-07:00</updated>
   <id>http://scottpatten.ca/2007/10/first-post</id>
   <content type="html">&lt;p&gt;I figured I needed to write a quick &amp;#8216;first post&amp;#8217; to introduce myself and spatten design.&lt;/p&gt;
&lt;p&gt;I’m Scott Patten. I’m a programmer, web developer and physicist.&lt;/p&gt;
&lt;p&gt;spatten design is where I post useful stuff I&amp;#8217;ve discovered or created.  I&amp;#8217;ll be writing about Ruby, Rails, Ajax, &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt;, Amazon Web services and, as it says in the side-bar, whatever else strikes my fancy.&lt;/p&gt;
&lt;p&gt;spatten design is also a Ruby on Rails &lt;a href=&quot;http://spattendesign.com/consulting&quot;&gt;consulting&lt;/a&gt; business.  I provide Ruby on Rails training and Ruby on Rails web development services.&lt;/p&gt;
&lt;p&gt;Besides the consulting work I do as spatten design, I also spend my time working on &lt;a href=&quot;www.plotomatic.com&quot;&gt;Plot-O-Matic&lt;/a&gt;, a scientific graphing web application written in Ruby on Rails. If you want to see what I can create, go check it out.&lt;/p&gt;
&lt;p&gt;Thanks for dropping by, and welcome.&lt;/p&gt;</content>
 </entry>
 
 
</feed>
