<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
  <title type="text">Jamie van Dyke</title>
  <generator uri="http://effectif.com/nesta">Nesta</generator>
  <id>tag:www.jamievandyke.com,2009:/</id>
  
  <link href="http://www.jamievandyke.com" rel="alternate" />
  <subtitle type="text">Ahhh, good arftanoon, sah!</subtitle>
  <author>
    <name>Jamie van Dyke</name>
    <uri>http://www.jamievandyke.com</uri>
    <email>jamie@fearoffish.com</email>
  </author>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/FearOfFish-RubyOnRails" /><feedburner:info uri="fearoffish-rubyonrails" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-sa/2.0/" /><feedburner:emailServiceId>FearOfFish-RubyOnRails</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><entry>
    <title>Contrary to the Rumors</title>
    <link type="text/html" href="http://feedproxy.google.com/~r/FearOfFish-RubyOnRails/~3/Md1XZKU-6j4/where-are-you-jamie" rel="alternate" />
    <id>tag:www.jamievandyke.com,2012-05-22:/where-are-you-jamie</id>
    <content type="html">&lt;p&gt;I&amp;#8217;m still alive! I&amp;#8217;ve been contracting for a Healthcare company in Nashville. I&amp;#8217;ve been doing a multitude of jobs, the timeline went something a little like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A month of web development&lt;/li&gt;

&lt;li&gt;Infrastructure development (cost reduction, increased redundancy, instance automation)&lt;/li&gt;

&lt;li&gt;Infrastructure Manager&lt;/li&gt;

&lt;li&gt;Captain of the Imaginarium (Research and Development)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last one is clearly the strangest title I chose, but it reflected what I do. Here&amp;#8217;s some examples of what I get tasked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;Give us geographical redundancy at a low cost&amp;#8221;&lt;/li&gt;

&lt;li&gt;&amp;#8220;Find a solution for Cynthia, see if you can automate that&amp;#8221;&lt;/li&gt;

&lt;li&gt;&amp;#8220;We need to send and receive faxes, both from a web app and from the desktop&amp;#8221;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I research each one, find possible solutions and then prototype them. The final choice is given to the Director.&lt;/p&gt;

&lt;h2 id='what_else_have_i_been_doing'&gt;What else have I been doing?&lt;/h2&gt;

&lt;p&gt;My main role has been as a DevOps, working with Amazon mostly. Their tools are fantastically designed to help reduce costs while increasing redundancy. I reduced the hosting costs by a third at PharmMD, increasing redundancy at the same time. I took an Advanced PostgreSQL course which helped understand how to architect the entire infrastructure.&lt;/p&gt;

&lt;p&gt;Amazon Cloud Formation, coupled with all the AWS tools is great for architecting a redundant, scalable framework. I&amp;#8217;ve also played with VMWare&amp;#8217;s CloudFoundry to reduce the lock-in you get with a vendor like that.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m currently looking around to see who else might need my services, I&amp;#8217;m available globally as I work from home. I&amp;#8217;m happy flying out for on-location work too, and can be hugely beneficial for initial planning and working closely with others.&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;re interested, get in touch through my contact details on the &amp;#8216;about me&amp;#8217; page. I&amp;#8217;m not immediately available, but I might be the one you need to plan the next stage of your infrastructure. I look forward to hearing from you.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Md1XZKU-6j4:5szDkItYTxo:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Md1XZKU-6j4:5szDkItYTxo:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Md1XZKU-6j4:5szDkItYTxo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=Md1XZKU-6j4:5szDkItYTxo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Md1XZKU-6j4:5szDkItYTxo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=Md1XZKU-6j4:5szDkItYTxo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Md1XZKU-6j4:5szDkItYTxo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=Md1XZKU-6j4:5szDkItYTxo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Md1XZKU-6j4:5szDkItYTxo:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=Md1XZKU-6j4:5szDkItYTxo:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FearOfFish-RubyOnRails/~4/Md1XZKU-6j4" height="1" width="1"/&gt;</content>
    <published>2012-05-22T19:39:15+01:00</published>
  <feedburner:origLink>http://www.jamievandyke.com/where-are-you-jamie</feedburner:origLink></entry>
  <entry>
    <title>Installing Bluepill</title>
    <link type="text/html" href="http://feedproxy.google.com/~r/FearOfFish-RubyOnRails/~3/1E49xIIn20I/want-some-campfire-with-that-bluepill" rel="alternate" />
    <id>tag:www.jamievandyke.com,2010-12-02:/want-some-campfire-with-that-bluepill</id>
    <content type="html">&lt;p&gt;We use &lt;a href='http://wiki.opscode.com/'&gt;Chef&lt;/a&gt; for automating our server infrastructure, but I&amp;#8217;ll show you the manual way of installing &lt;a href='https://github.com/arya/bluepill'&gt;Bluepill&lt;/a&gt; (either locally or remotely) so you can play with it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ gem install bluepill&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That wasn&amp;#8217;t hard, was it? Dependencies will be resolved, and installed too. Now we&amp;#8217;ve got it installed, let&amp;#8217;s take a little look at the commands we can give it.&lt;/p&gt;

&lt;p&gt;Check the status of all applications and processes&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo bluepill status&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Start all applications and stop all applications, or a single group.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo bluepill start
$ sudo bluepill stop
$ sudo bluepill start resque&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Quit Bluepill.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo bluepill quit&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You configure Bluepill with a configuration file. Here&amp;#8217;s one we use to start multiple &lt;a href='https://github.com/defunkt/resque'&gt;resque&lt;/a&gt; queues. It&amp;#8217;s a work in progress but does what we want for now. I won&amp;#8217;t explain the config file because there&amp;#8217;s plenty of blogs (and of course the Bluepill README) that go into detail here.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;queues = {}
queues[&amp;quot;comms&amp;quot;] = 1
queues[&amp;quot;rules&amp;quot;] = 2
queues[&amp;quot;patients&amp;quot;] = 4
queues[&amp;quot;import&amp;quot;] = 1

@app_name   = &amp;quot;pharmmd&amp;quot;
@owner_name = &amp;quot;rails&amp;quot;
@rails_env  = &amp;quot;production&amp;quot;
@rake_command = &amp;quot;bundle exec rake &amp;quot;

Bluepill.application(&amp;quot;#{@app_name}_resque&amp;quot;, :log_file =&amp;gt; &amp;quot;/var/log/bluepill.log&amp;quot;) do |app|
  app.uid = app.gid = @owner_name

  queues.each do |queue, count|
    count.times.each do |idx|
      app.process(&amp;quot;resque_worker_#{queue}_#{idx}&amp;quot;) do |process|
        process.group = &amp;#39;resque&amp;#39;
        process.pid_file = &amp;quot;/var/run/resque/#{@app_name}/worker_#{queue}_#{idx}.pid&amp;quot;
        process.working_dir = &amp;quot;/data/#{@app_name}/current&amp;quot;
        process.start_command = @rake_command +
          &amp;quot;RACK_ENV=#{@rails_env} RAILS_ENV=#{@rails_env} &amp;quot; +
          &amp;quot;QUEUE=#{queue} &amp;quot; +
          &amp;quot;resque:work&amp;quot;
        process.stop_command = &amp;lt;&amp;lt;-EOF
        kill -QUIT {{PID}}
        sleep_count=0
        while [ -e /proc/{{PID}} ]; do
          sleep 1
          let &amp;quot;sleep_count+=1&amp;quot;
          if [ $sleep_count -eq 60 ]; then
            kill -TERM {{PID}}
          fi
          if [ $sleep_count -ge 70 ]; then
            kill -KILL {{PID}}
          fi
        done
        EOF
        process.start_grace_time = 5.seconds
        process.stop_grace_time = 75.seconds
        process.restart_grace_time = 80.seconds
        process.daemonize = true

        process.checks :mem_usage, :below =&amp;gt; 150.megabytes, :every =&amp;gt; 1.minute, :times =&amp;gt; 3
      end
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What I wanted to add was a notification system that let me know when things had gone horribly wrong. Specifically I wanted &lt;a href='http://campfirenow.com/'&gt;Campfire&lt;/a&gt; notifications, as that&amp;#8217;s where all the cool techies at &lt;a href='http://www.pharmmd.com/'&gt;PharmMD&lt;/a&gt; hang out.&lt;/p&gt;

&lt;p&gt;For notifications, &lt;a href='https://github.com/arya/bluepill'&gt;Bluepill&lt;/a&gt; allows us to write simple &amp;#8216;Triggers&amp;#8217;. These triggers can be added to a process in the config file, like zoh:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;process.checks :some_trigger, :every =&amp;gt; 1.minute&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So let&amp;#8217;s add a &lt;a href='http://campfirenow.com/'&gt;Campfire&lt;/a&gt; notifier. First things first, I&amp;#8217;ll be using the &lt;a href='https://github.com/collectiveidea/tinder'&gt;tinder&lt;/a&gt; gem to talk to Campfire, have a look at their README for details on how it works (or the excellent &lt;a href='http://tinder.rubyforge.org/'&gt;tinder homepage&lt;/a&gt;). Install tinder.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ gem install tinder&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At the top of the &lt;a href='https://github.com/arya/bluepill'&gt;Bluepill&lt;/a&gt; config file (anywhere above the application block) add the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require &amp;#39;rubygems&amp;#39;
require &amp;#39;uri&amp;#39;
require &amp;#39;tinder&amp;#39;

class Campfire &amp;lt; Bluepill::Trigger
  PARAMS = [:times, :within, :retry_in, :rails_env]

  attr_accessor *PARAMS

  def initialize(process, options = {})
    options.reverse_merge!(:times =&amp;gt; 5, :within =&amp;gt; 1, :retry_in =&amp;gt; 5)

    options.each_pair do |name, val|
      instance_variable_set(&amp;quot;@#{name}&amp;quot;, val) if PARAMS.include?(name)
    end

    super
  end
  def notify(transition)
    @logger.info &amp;quot;I so just got triggered with a transition!&amp;quot;
    begin
      if transition.to == &amp;quot;down&amp;quot; &amp;amp;&amp;amp; transition.from == &amp;quot;up&amp;quot;
        @logger.info &amp;quot;BluePill: #{@rails_env} worker(#{process.name}) went from #{transition.from_name} to #{transition.to_name}. Restarting them.&amp;quot;
        campfire = Tinder::Campfire.new &amp;#39;pharmmd&amp;#39;, :token =&amp;gt; &amp;#39;TOKEN&amp;#39;
        room     = campfire.find_room_by_name(&amp;#39;General&amp;#39;)
        room.speak &amp;quot;BluePill: #{@rails_env} worker(#{process.name}) died. Restarting it.&amp;quot;
      end
    rescue =&amp;gt; x
      @logger.info &amp;quot;Totally failed with: #{x.message}&amp;quot;
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the &lt;code&gt;initialize&lt;/code&gt; method I set up some parameters that I can pass in, as well as provide myself with some defaults to fall back on.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PARAMS = [:times, :within, :retry_in, :rails_env]
attr_accessor *PARAMS&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I create instance variables for each option for access later on, and call super to allow the Bluepill::Trigger class to do its own initialisation.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;options.each_pair do |name, val|
  instance_variable_set(&amp;quot;@#{name}&amp;quot;, val) if PARAMS.include?(name)
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next up I create one of the required methods that Bluepill will call periodically and sprinkle in a little logging (&lt;code&gt;@logger&lt;/code&gt; is provided by Bluepill::Trigger).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@logger.info &amp;quot;I so just got triggered with a transition!&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next up we wrap our &lt;a href='http://campfirenow.com/'&gt;Campfire&lt;/a&gt; notification in a rescue block, because we don&amp;#8217;t want ay silly exceptions like a lack of net access from bombing Bluepill out. There are a few transitions we can use, the important one for me is when a process dies (even though Bluepill will restart it), I want to know when that happens so I can find out why and stop it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if transition.to == &amp;quot;down&amp;quot; &amp;amp;&amp;amp; transition.from == &amp;quot;up&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Tinder makes campfire access so simple. Connect to campfire, select a room, and then &amp;#8216;speak&amp;#8217; into it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; campfire = Tinder::Campfire.new &amp;#39;pharmmd&amp;#39;, :token =&amp;gt; &amp;#39;TOKEN&amp;#39;
 room     = campfire.find_room_by_name(&amp;#39;General&amp;#39;)
 room.speak &amp;quot;BluePill: #{@rails_env} worker(#{process.name}) died. Restarting it.&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;#8217;s it for the trigger. Now all we need to do is tell the process that it should fire that trigger. Add the following to the process block just beneath where we checked for memory usage.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;process.checks :campfire, :rails_env =&amp;gt; @rails_env&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;#8217;s it. Now when you load the config file in, Campfire will get notifications if the process needs restarting.&lt;/p&gt;

&lt;p&gt;Simple Campfire notifications using Tinder and Bluepill? Done.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=1E49xIIn20I:vI32r2x9if8:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=1E49xIIn20I:vI32r2x9if8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=1E49xIIn20I:vI32r2x9if8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=1E49xIIn20I:vI32r2x9if8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=1E49xIIn20I:vI32r2x9if8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=1E49xIIn20I:vI32r2x9if8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=1E49xIIn20I:vI32r2x9if8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=1E49xIIn20I:vI32r2x9if8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=1E49xIIn20I:vI32r2x9if8:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=1E49xIIn20I:vI32r2x9if8:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FearOfFish-RubyOnRails/~4/1E49xIIn20I" height="1" width="1"/&gt;</content>
    <published>2010-12-02T14:14:01+00:00</published>
  <feedburner:origLink>http://www.jamievandyke.com/want-some-campfire-with-that-bluepill</feedburner:origLink></entry>
  <entry>
    <title>Getting gource installed using home brew</title>
    <link type="text/html" href="http://feedproxy.google.com/~r/FearOfFish-RubyOnRails/~3/A5vk1AWMVdI/visualise-your-git-log-with-some-pew-pew-pew" rel="alternate" />
    <id>tag:www.jamievandyke.com,2010-11-18:/visualise-your-git-log-with-some-pew-pew-pew</id>
    <content type="html">&lt;p&gt;&lt;a href='http://code.google.com/p/gource/'&gt;Gource&lt;/a&gt; is an OpenGL capable visualisation tool for difference SCM&amp;#8217;s, it&amp;#8217;s easy to install and looks pretty damn cool. If you have &lt;a href='https://github.com/mxcl/homebrew'&gt;Homebrew&lt;/a&gt; installed it&amp;#8217;s simply:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ brew install gource&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which happily goes off and grabs all the dependencies like pkg-config, libpng and others. Once it&amp;#8217;s done, change into your projects directory (I&amp;#8217;m assuming you use &lt;a href='http://git-scm.com/'&gt;git&lt;/a&gt;) and then run gource.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cd /projects/myproject
$ gource&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then watch the asteroids takes on space invaders style 3D visualisation of your developers doing their thaaang. If you want to make it cooler, then how about a little perl script to grab gravatars for each of your developers and make it more personal? On the gource google code project wiki there&amp;#8217;s a script for just that, grab it off &lt;a href='http://code.google.com/p/gource/wiki/GravatarExample'&gt;this page&lt;/a&gt; and save it as &lt;code&gt;grab_avatars.pl&lt;/code&gt; and run it on your commandline.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ perl grab_avatars.pl&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;#8217;ll grab all of the gravatars for each developer and then save them in a &lt;code&gt;.git/avatars&lt;/code&gt; folder, now we just need to tell gource to use that and we&amp;#8217;re laffin&amp;#8217;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ gource --user-image-dir .git/avatar/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For an example of what it looks like, here&amp;#8217;s a snippet of our project with some developers PEW PEWing at the code:&lt;/p&gt;
&lt;embed href='http://s3.amazonaws.com/jamievandyke-blog-assets/pewpew-with-gource.mov' src='http://s3.amazonaws.com/jamievandyke-blog-assets/pewpew-with-gource.mov' autoplay='false' height='694px' controller='true' loop='false' target='quicktimeplayer' width='766px' /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=A5vk1AWMVdI:zJuEcZ6y5gA:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=A5vk1AWMVdI:zJuEcZ6y5gA:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=A5vk1AWMVdI:zJuEcZ6y5gA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=A5vk1AWMVdI:zJuEcZ6y5gA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=A5vk1AWMVdI:zJuEcZ6y5gA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=A5vk1AWMVdI:zJuEcZ6y5gA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=A5vk1AWMVdI:zJuEcZ6y5gA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=A5vk1AWMVdI:zJuEcZ6y5gA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=A5vk1AWMVdI:zJuEcZ6y5gA:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=A5vk1AWMVdI:zJuEcZ6y5gA:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FearOfFish-RubyOnRails/~4/A5vk1AWMVdI" height="1" width="1"/&gt;</content>
    <published>2010-11-18T22:26:02+00:00</published>
  <feedburner:origLink>http://www.jamievandyke.com/visualise-your-git-log-with-some-pew-pew-pew</feedburner:origLink></entry>
  <entry>
    <title>Engine Yard AppCloud Experiences</title>
    <link type="text/html" href="http://feedproxy.google.com/~r/FearOfFish-RubyOnRails/~3/cd17VOhyN5I/what-an-engine-yard-appcloud-experience" rel="alternate" />
    <id>tag:www.jamievandyke.com,2010-07-20:/what-an-engine-yard-appcloud-experience</id>
    <content type="html">&lt;h2 id='in_summary'&gt;In Summary&lt;/h2&gt;

&lt;p&gt;As most of you probably know, I used to work at Engine Yard. The developers there are super intelligent and super knowledgeable and I loved working with them. Their vision for the AppCloud is a great idea in practise. To be able to scale your app as traffic increases and decreases, to replace broken server instances at the click of a button, this is the dream. Now the bad news. &lt;em&gt;It&amp;#8217;s unstable, woefully under-tested and not production ready.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id='in_detail'&gt;In Detail&lt;/h2&gt;

&lt;p&gt;The client I was working with was working with medium sized clusters of instances, of varying sizes but usually along the lines of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 App server (64 bit CPU, 8 ECU&amp;#8217;s, 15GB RAM, 1.7TB Persistent Storage)&lt;/li&gt;

&lt;li&gt;1 DB Server (64 bit CPU, 13 ECU&amp;#8217;s, 34GB RAM, 850GB Persistent Storage)&lt;/li&gt;

&lt;li&gt;1 Mongo Instance (64 bit CPU, 20 ECU&amp;#8217;s, 7GB RAM, 1.7TB Persistent Storage)&lt;/li&gt;

&lt;li&gt;1 Util Instance Server (64 bit CPU, 13 ECU&amp;#8217;s, 34GB RAM, 850GB Persistent Storage)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are about 6-7 of these clusters, costing well into the 10&amp;#8217;s of thousands a month. Don&amp;#8217;t worry about the setup because I didn&amp;#8217;t design it, the previous contractors did. We&amp;#8217;re in the middle of a re-design now, e.g. we should 2 application servers for redundancy. We should be able to do this on the fly but this requires some manual DevOps to take place, specifically we need custom chef recipes to handle things that have been done manually, and this hasn&amp;#8217;t been done yet.&lt;/p&gt;

&lt;p&gt;Now in theory the AppCloud dashboard should also be able to clone an entire environment so you can run test deploys and more on it. In my experience those clones worked 1 day out of 7, the other times I was met with cryptic messages like &lt;em&gt;&amp;#8220;There was an unexpected error while provisioning your instance.&amp;#8221;&lt;/em&gt;. Not terribly useful. Some of them worked sometimes, others failed. It turns out that for us the unexpected errors were one or all of the following at different times spread over a few weeks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reaching the Amazon EC2 EBS Device storage limit (20TB)&lt;/li&gt;

&lt;li&gt;Reaching the Amazon EC2 API limit (due to having a few people using the dashboard at the same time)&lt;/li&gt;

&lt;li&gt;One of many unknown dashboard errors&lt;/li&gt;

&lt;li&gt;The data from a utility instance mounted on the application instance (!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let&amp;#8217;s look at a few of these in detail.&lt;/p&gt;

&lt;h3 id='reaching_the_amazon_ec2_ebs_device_storage_limit_20tb'&gt;Reaching the Amazon EC2 EBS Device storage limit (20TB)&lt;/h3&gt;

&lt;p&gt;That&amp;#8217;s a huge amount of data, I know! How did the client come to get so much data, well they used EBS snapshots as backups. That&amp;#8217;s crazy considering they range from 256GB to 512GB, and they need to keep them all! Snapshots are done daily automatically, but usually someone will fire off a snapshot at some other time during the day. Meaning every day the amount of data that is held in snapshots increases by about 2TB, instead of being pushed up to S3 (another TODO that needs sorting). So the Amazon EC2 limit was hit, which is not Engine Yard&amp;#8217;s fault but they should have some API warnings in the dashboard so we know what&amp;#8217;s happening. Otherwise errors like the next one pop up too.&lt;/p&gt;

&lt;h3 id='reaching_the_amazon_ec2_api_limit'&gt;Reaching the Amazon EC2 API limit&lt;/h3&gt;

&lt;p&gt;Too many queries at one time will get you temporarily banned from EC2 API queries and commands. That makes sense, but not when we don&amp;#8217;t know how much of the query limit we&amp;#8217;ve used. If you don&amp;#8217;t grasp the horrors of not knowing, let&amp;#8217;s just say if you bring the production cluster down for some quick maintenance (resizing EBS devices for example, which requires a terminate and rebuild) and you hit your limit before it comes back up&amp;#8230;.bad news, your cluster isn&amp;#8217;t going to rebuild. On top of that, while it&amp;#8217;s failing to rebuild you&amp;#8217;ll probably terminate the cluster in the dashboard and try again which just prolongs the problem.&lt;/p&gt;

&lt;p&gt;It turns out this problem was due to the dashboard making too many queries (polling Amazon for data regularly), note the past tense, the Engine Yard developers promise me that this error has gone away now.&lt;/p&gt;

&lt;h3 id='one_of_many_unknown_dashboard_errors'&gt;One of many unknown dashboard errors&lt;/h3&gt;

&lt;p&gt;On many occasions I would see a 500 error page when trying to use their dashboard, and when I asked their support guys what was up the answer was usually &amp;#8220;We need to roll back a new version of the dashboard we just pushed&amp;#8221;. Seriously, this happened on a multitude of times. You lose your confidence after number 3 I can tell you.&lt;/p&gt;

&lt;p&gt;There needs to be more testing done for different scenarios if it&amp;#8217;s going to break so regularly. From their point of view I guess they will say it&amp;#8217;s because of the Amazon backend and the cryptic API responses they get sometimes. Sure, but I don&amp;#8217;t care about that. If you choose to use Amazon EC2 as your backend for a cloud service, you better be damn sure you know exactly what&amp;#8217;s what before using it!&lt;/p&gt;

&lt;h3 id='the_data_from_a_utility_instance_mounted_on_the_application_instance_'&gt;The data from a utility instance mounted on the application instance (!)&lt;/h3&gt;

&lt;p&gt;Oh, this one was just brilliant. 1 week the problem was that if you wanted to boot a cluster from old snapshots, the utility instances couldn&amp;#8217;t actually re-attach old snapshots, it had to be done manually. That one sort of scared me a little because I was in the middle of production deploy testing when I was informed of it.&lt;/p&gt;

&lt;p&gt;After they fixed the above issue in the dashboard, they introduced a brand new one. I cloned an environment and when it came online the utility instance had no data, which threw me. Until I looked on the application instance and found what should have been mounted to the utility instance. How exactly does this go wrong so badly?!&lt;/p&gt;

&lt;h2 id='however'&gt;However&amp;#8230;&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m obliged to say again, the developers and support people over at Engine Yard are fantastic, but clearly this product has a long way to go before it can be used for large applications of any sort. If you are working with a smaller application it makes sense to use them, but as your application grows, hope to the Gods that they&amp;#8217;ve matured it slightly.&lt;/p&gt;

&lt;p&gt;The moral of the story here is simple and something you all know already. &lt;em&gt;If you can&amp;#8217;t rely on something 100% then don&amp;#8217;t use it in production&lt;/em&gt;. This is a hard lesson that my client has learnt and suffered greatly from. The client is (of course) trying out other services from different providers to move off the AppCloud platform. More on that in the future.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&amp;#8217;re looking for help with Application deployment, please do &lt;a href='&amp;#109;&amp;#97;&amp;#105;&amp;#108;&amp;#116;&amp;#111;&amp;#58;&amp;#106;&amp;#97;&amp;#109;&amp;#105;&amp;#101;&amp;#64;&amp;#102;&amp;#101;&amp;#97;&amp;#114;&amp;#111;&amp;#102;&amp;#102;&amp;#105;&amp;#115;&amp;#104;&amp;#46;&amp;#99;&amp;#111;&amp;#109;'&gt;&amp;#103;&amp;#101;&amp;#116;&amp;#32;&amp;#105;&amp;#110;&amp;#32;&amp;#116;&amp;#111;&amp;#117;&amp;#99;&amp;#104;&lt;/a&gt; and I&amp;#8217;ll see what I can do for you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=cd17VOhyN5I:bB-0qnFPysk:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=cd17VOhyN5I:bB-0qnFPysk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=cd17VOhyN5I:bB-0qnFPysk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=cd17VOhyN5I:bB-0qnFPysk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=cd17VOhyN5I:bB-0qnFPysk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=cd17VOhyN5I:bB-0qnFPysk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=cd17VOhyN5I:bB-0qnFPysk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=cd17VOhyN5I:bB-0qnFPysk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=cd17VOhyN5I:bB-0qnFPysk:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=cd17VOhyN5I:bB-0qnFPysk:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FearOfFish-RubyOnRails/~4/cd17VOhyN5I" height="1" width="1"/&gt;</content>
    <published>2010-07-20T20:39:15+00:00</published>
  <feedburner:origLink>http://www.jamievandyke.com/what-an-engine-yard-appcloud-experience</feedburner:origLink></entry>
  <entry>
    <title>Get in touch with me</title>
    <link type="text/html" href="http://feedproxy.google.com/~r/FearOfFish-RubyOnRails/~3/Oq3GtbwpUos/me" rel="alternate" />
    <id>tag:www.jamievandyke.com,2010-04-15:/about/me</id>
    <content type="html">&lt;p&gt;The easiest way to get in touch with me, is to email me through my business email address, which is &amp;#106;&amp;#97;&amp;#109;&amp;#105;&amp;#101;&amp;#64;&amp;#102;&amp;#101;&amp;#97;&amp;#114;&amp;#111;&amp;#102;&amp;#102;&amp;#105;&amp;#115;&amp;#104;&amp;#46;&amp;#99;&amp;#111;&amp;#109;&lt;/p&gt;

&lt;h1 id='you_want_to_know_about_me'&gt;You want to know about me?&lt;/h1&gt;

&lt;h2 id='current_status'&gt;Current Status&lt;/h2&gt;

&lt;p&gt;For the past 2 years I&amp;#8217;ve been contracting for a Healthcare company (&lt;a href='http://www.pharmmd.com/'&gt;PharmMD&lt;/a&gt;) as the Infrastructure Manager. I&amp;#8217;ve reduced hosting costs to a third of the cost from when I arrived, as well as increasing redundancy over the board. I used Amazon Web Services as well as Opscode&amp;#8217;s Chef to reduce those costs and automate the build of over 100 server instances.&lt;/p&gt;

&lt;h2 id='key_skills'&gt;Key Skills&lt;/h2&gt;

&lt;p&gt;So now you know about &lt;em&gt;me&lt;/em&gt;, here&amp;#8217;s some key parts of the past 7 years that you might find useful when judging if I&amp;#8217;m the man you need for a job.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Since the beginning of 2005 I&amp;#8217;ve been using &lt;a href='http://www.ruby-lang.org/'&gt;Ruby&lt;/a&gt; and &lt;a href='http://www.rubyonrails.org/'&gt;Rails&lt;/a&gt; on a daily basis&lt;/li&gt;

&lt;li&gt;Skilled in hosting and deployment&lt;/li&gt;

&lt;li&gt;Ruby on Rails Teacher for &lt;a href='http://www.skillsmatter.com/'&gt;Skillsmatter&lt;/a&gt; both solo and alongside &lt;a href='http://rubypal.com/'&gt;David Black&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://contributors.rubyonrails.org/contributors/jamie-van-dyke/commits'&gt;Rails Contributor&lt;/a&gt; with documentation and patches&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.engineyard.com/'&gt;Engine Yard&lt;/a&gt; App Support Manager, EU (Built up the EU team)&lt;/li&gt;

&lt;li&gt;CTO at &lt;a href='http://www.venturian-media.com/'&gt;Venturian Media&lt;/a&gt;, planned and re-wrote &lt;a href='http://www.boxedup.com/'&gt;Boxedup&lt;/a&gt; using &lt;a href='http://www.mongodb.org/'&gt;MongoDB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='hunt_me_down_on_the_internet'&gt;Hunt me down on the internet&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://www.linkedin.com/in/fearoffish'&gt;LinkedIn&lt;/a&gt; (Recommended by 22 people)&lt;/li&gt;

&lt;li&gt;&lt;a href='http://workingwithrails.com/person/5466-jamie-van-dyke'&gt;Working with Rails&lt;/a&gt; (Recommended by 53 people)&lt;/li&gt;

&lt;li&gt;&lt;a href='http://github.com/fearoffish/'&gt;GitHub&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.twitter.com/fearoffish/'&gt;Twitter&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.railsmentors.org/users/404'&gt;Rails Mentors&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://rubylearning.com/blog/2010/04/07/rpcfn-xml-transformer-8/'&gt;Ruby Programming Challenge&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.google.com/search?q=%22Jamie+van+Dyke%22'&gt;Google&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='interviews'&gt;Interviews&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://rubylearning.com/blog/2008/09/23/little-known-ways-to-ruby-mastery-by-jamie-van-dyke/'&gt;Ruby Learning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='conference_talks'&gt;Conference Talks&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://en.oreilly.com/rails2008/public/schedule/speaker/2863'&gt;RailsConf 2008&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://epicenter.ie/2010.html?zone_id=21&amp;amp;speaker=128'&gt;Epicenter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='external_articles'&gt;External Articles&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://therubyist.com/'&gt;The Rubyist&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='i_get_personal'&gt;I get personal&lt;/h2&gt;
&lt;div style='float:right'&gt;&lt;img src='/images/jamie.jpeg' style='height:200px;margin:20px' /&gt;&lt;/div&gt;
&lt;p&gt;I&amp;#8217;m Jamie van Dyke. I was born in the North of England in a little town called Steeton. My Father was Dutch (he passed away) and my Mother is British. I&amp;#8217;m in my early thirties and my hair is balding slightly at the back, which is a little depressing. I only have two children as far as I&amp;#8217;m aware, they are Lex (my son, who is 4) and Liesel (my Daughter, who is 12). I&amp;#8217;m engaged to Kelly Baker who is clearly a little dizzy because she wants to marry me!&lt;/p&gt;

&lt;p&gt;And now for the Ugly Truth. I&amp;#8217;m a grumpy man with a twist of humour, I&amp;#8217;ll make you laugh but I&amp;#8217;m one hell of a cynic! I strive for perfection in most of the things I do and I&amp;#8217;m continuously disappointed with other&amp;#8217;s attitude toward those around them. I don&amp;#8217;t think I&amp;#8217;m the best Father in the world, nor am I the best partner or worker, but I work as hard as I can to be them. What I would say though is that I&amp;#8217;m a lot like &lt;a href='http://www.marmite.com/'&gt;Marmite&lt;/a&gt;, you either love me or hate me and there&amp;#8217;s very rarely a middle ground. I&amp;#8217;m extremely helpful, but suffer from an inability to say &amp;#8220;no&amp;#8221; to those that need my help, so sometimes I spread myself too thin with too many things to do. I apologise for that.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Oq3GtbwpUos:XrU3ENXhmVI:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Oq3GtbwpUos:XrU3ENXhmVI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Oq3GtbwpUos:XrU3ENXhmVI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=Oq3GtbwpUos:XrU3ENXhmVI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Oq3GtbwpUos:XrU3ENXhmVI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=Oq3GtbwpUos:XrU3ENXhmVI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Oq3GtbwpUos:XrU3ENXhmVI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=Oq3GtbwpUos:XrU3ENXhmVI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=Oq3GtbwpUos:XrU3ENXhmVI:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=Oq3GtbwpUos:XrU3ENXhmVI:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FearOfFish-RubyOnRails/~4/Oq3GtbwpUos" height="1" width="1"/&gt;</content>
    <published>2010-04-15T15:24:29+01:00</published>
  <feedburner:origLink>http://www.jamievandyke.com/about/me</feedburner:origLink></entry>
  <entry>
    <title>Making your /etc/hostnames life easier</title>
    <link type="text/html" href="http://feedproxy.google.com/~r/FearOfFish-RubyOnRails/~3/JllrUdp18QI/ghost-and-local-hostnames" rel="alternate" />
    <id>tag:www.jamievandyke.com,2010-02-08:/ghost-and-local-hostnames</id>
    <content type="html">&lt;p&gt;I was just reading &lt;a href='http://samsoff.es/post/running-rails-local-development-with-nginx-postgres-and-passenger-with-homebrew'&gt;running rails local development with nginx, postgres, and passenger with homebrew&lt;/a&gt; on Sam Soffes site, and found it very useful for a quick copy and paste of his configs.&lt;/p&gt;

&lt;p&gt;One thing that I found strange though is that he is using &lt;code&gt;/etc/hosts&lt;/code&gt; to make local hostnames for web development. If you haven&amp;#8217;t found out about the &lt;code&gt;ghost&lt;/code&gt; gem yet:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;➜  /  gem install ghost --no-ri --no-rdoc 
Successfully installed ghost-0.2.4
1 gem installed
➜  /  ghost add blah.local
  [Adding] blah.local -&amp;gt; 127.0.0.1
➜  /  ghost list
Listing 1 host(s):
                 blah.local -&amp;gt; 127.0.0.1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;No need to piss about with your &lt;code&gt;/etc/hosts&lt;/code&gt; file anymore, this is as simple as it gets.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=JllrUdp18QI:ARUtLytDOYM:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=JllrUdp18QI:ARUtLytDOYM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=JllrUdp18QI:ARUtLytDOYM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=JllrUdp18QI:ARUtLytDOYM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=JllrUdp18QI:ARUtLytDOYM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=JllrUdp18QI:ARUtLytDOYM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=JllrUdp18QI:ARUtLytDOYM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=JllrUdp18QI:ARUtLytDOYM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=JllrUdp18QI:ARUtLytDOYM:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=JllrUdp18QI:ARUtLytDOYM:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FearOfFish-RubyOnRails/~4/JllrUdp18QI" height="1" width="1"/&gt;</content>
    <published>2010-02-08T19:26:02+01:00</published>
  <feedburner:origLink>http://www.jamievandyke.com/ghost-and-local-hostnames</feedburner:origLink></entry>
  <entry>
    <title>uninitialized constant Rails::Railtie</title>
    <link type="text/html" href="http://feedproxy.google.com/~r/FearOfFish-RubyOnRails/~3/9lRemamrW4Y/the-inherited-resources-railties-error" rel="alternate" />
    <id>tag:www.jamievandyke.com,2010-02-08:/the-inherited-resources-railties-error</id>
    <content type="html">&lt;p&gt;If you&amp;#8217;re like me and you skip reading a gem&amp;#8217;s README when you install the latest, you&amp;#8217;ll be seriously sorry when you don&amp;#8217;t for &lt;a href='http://github.com/josevalim/inherited_resources'&gt;inherited_resources&lt;/a&gt; because it is Rails 3 only. The same can be said for &lt;a href='http://github.com/plataformatec/responders'&gt;responders&lt;/a&gt;. You&amp;#8217;ll get a big fat punch in the face with this error:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;uninitialized constant Rails::Railtie&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But fear not, just reverting to the following version will get you back on track:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;quot;inherited_resources&amp;quot;, :version =&amp;gt; &amp;quot;1.0.0&amp;quot;
&amp;quot;responders&amp;quot;, :version =&amp;gt; &amp;quot;0.4.0&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, on your bike. Get back to work!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=9lRemamrW4Y:Yx_AB5Ci2Gc:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=9lRemamrW4Y:Yx_AB5Ci2Gc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=9lRemamrW4Y:Yx_AB5Ci2Gc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=9lRemamrW4Y:Yx_AB5Ci2Gc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=9lRemamrW4Y:Yx_AB5Ci2Gc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=9lRemamrW4Y:Yx_AB5Ci2Gc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=9lRemamrW4Y:Yx_AB5Ci2Gc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=9lRemamrW4Y:Yx_AB5Ci2Gc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=9lRemamrW4Y:Yx_AB5Ci2Gc:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=9lRemamrW4Y:Yx_AB5Ci2Gc:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FearOfFish-RubyOnRails/~4/9lRemamrW4Y" height="1" width="1"/&gt;</content>
    <published>2010-02-08T18:13:57+01:00</published>
  <feedburner:origLink>http://www.jamievandyke.com/the-inherited-resources-railties-error</feedburner:origLink></entry>
  <entry>
    <title>Web Development with Source Code Management Basics</title>
    <link type="text/html" href="http://feedproxy.google.com/~r/FearOfFish-RubyOnRails/~3/KUWf3pw_WVA/web-development-with-source-code-management-a-basic-guide" rel="alternate" />
    <id>tag:www.jamievandyke.com,2009-08-30:/web-development-with-source-code-management-a-basic-guide</id>
    <content type="html">&lt;h2 id='preamble'&gt;Pre-Amble&lt;/h2&gt;

&lt;p&gt;I remember when I first started development. Even more fun was doing the same but over a remote ftp connection through Transmit, or just directly on the server. I got used to pretty GUI&amp;#8217;s doing things for me and visually feedback for whether I&amp;#8217;d got it right. Oh, how things have changed. My work flow was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make changes to my code&lt;/li&gt;

&lt;li&gt;Flip to my browser and refresh&lt;/li&gt;

&lt;li&gt;See what I&amp;#8217;ve done has changed&lt;/li&gt;

&lt;li&gt;Go back to my code and make more changes&lt;/li&gt;

&lt;li&gt;Go back to my browser and refresh&lt;/li&gt;

&lt;li&gt;See I broke stuff&lt;/li&gt;

&lt;li&gt;Go back and try fix it&lt;/li&gt;

&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I want to take you through how a basic version of what I do now, and the benefits of what I do. I have confidence in my changes and a general feeling of happiness that I&amp;#8217;d like to pass on to you. Whether or not I work in a team, I use distributed version managed code to do so. Any changes I make locally are pushed to a remote computer, why? What if my hard drive failed or I&amp;#8217;m working on another machine for the day, you never know. Either way, I have access to my code, including all the changes I&amp;#8217;ve made.&lt;/p&gt;

&lt;p&gt;Why was my initial plan inefficient? Well, it was brittle and to test everything meant looking at all the pages sequentially. Making changes in one place might affect another and I had to double check it manually. Also, the changes I made weren&amp;#8217;t reversible. I worked around that by saving multiple copies of my files or folders, keeping old version of sites hanging around so I could always revert back if I wanted. &lt;em&gt;This just doesn&amp;#8217;t scale&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;What&amp;#8217;s the alternative? Source Code Management. There are many systems around and I&amp;#8217;ve certainly used a myriad of them, but I&amp;#8217;ve settled on &lt;a href='http://www.git-scm.org/'&gt;git&lt;/a&gt; which makes me warm and fuzzy inside. Git was developed initially by Linus Torvalds to manage the complicated process of building a Linux kernel in a distributed manner (multiple people, multiple places editing one set of files). Quick list of benefits we&amp;#8217;re interested in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Revert changes without saving different versions manually&lt;/li&gt;

&lt;li&gt;Develop multiple version of your site concurrently&lt;/li&gt;

&lt;li&gt;Log changes you&amp;#8217;ve made without a separately managed log file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enough talk, let&amp;#8217;s just run through what I do. I use &lt;a href='http://www.rubyonrails.org/'&gt;Ruby on Rails&lt;/a&gt; and &lt;a href='http://www.sinatrarb.com/'&gt;Sinatra&lt;/a&gt; for web development, but this will work with most languages too, if not all.&lt;/p&gt;

&lt;h2 id='getting_setup'&gt;Getting Setup&lt;/h2&gt;

&lt;p&gt;Create a new project in your tool of choice, I&amp;#8217;ll create one called &amp;#8216;scm_project&amp;#8217; with Ruby on Rails:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ rails scm_project
create  
create  app/controllers
...
create  log/test.log&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is just a plain old Ruby on Rails project, but it could be anything for you, even just a folder with some php files. We need to initialise the folder with our source code manager &amp;#8216;git&amp;#8217;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cd scm_project
scm_project $ git init
Initialized empty Git repository in /a/demos/scm_project/.git/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So git has set up our folder as a version managed folder. We can now, for example, ask git for the status of this folder:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use &amp;quot;git add &amp;lt;file&amp;gt;...&amp;quot; to include in what will be committed)
#
#	README
#	Rakefile
#	app/
#	config/
#	doc/
#	log/
#	public/
#	script/
#	test/
nothing added to commit but untracked files present (use &amp;quot;git add&amp;quot; to track)&amp;lt;/pre&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Don&amp;#8217;t worry, this is nothing scary. It&amp;#8217;s just telling me that this folder has some unmanaged (&amp;#8216;untracked&amp;#8217;) files. Source code managers need to told which files they&amp;#8217;re managing. In this case we just need to tell git what to add and what to ignore. Some things shouldn&amp;#8217;t be added, for example a database credentials file. If you have multiple people on a project and you all have your own local database server, then there&amp;#8217;s no guarantee that the access details are the same, so by leaving it out (telling git to ignore it) it will never be added and everyone can have their own version without it affecting others.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s set up our file ignore list. Create a file in the root of that folder called &lt;code&gt;.gitignore&lt;/code&gt; and put in contents like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;log/*.log
tmp/
.DS_Store
doc/api
doc/app
doc/plugins
db/*.sqlite3
config/database.yml&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is my base &lt;code&gt;.gitignore&lt;/code&gt; file, you can add to this later as you go. The idea is that anything you don&amp;#8217;t want version managed, you add to this file.&lt;/p&gt;

&lt;p&gt;Next up, we need to tell the version management to add all files.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;scm_project $ 
scm_project $ git add .
scm_project $ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use &amp;quot;git rm --cached &amp;lt;file&amp;gt;...&amp;quot; to unstage)
#
#	new file:   .gitignore
#	new file:   README
...
#	new file:   test/performance/browsing_test.rb
#	new file:   test/test_helper.rb
#&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So by running &lt;code&gt;git add .&lt;/code&gt; we&amp;#8217;re telling git to add everything within this directory. &lt;code&gt;.&lt;/code&gt; means &amp;#8216;this directory&amp;#8217; in linux talk. That&amp;#8217;s easy enough. Adding files to git means you&amp;#8217;re telling it what you want to store in the system, but you need to &amp;#8216;commit&amp;#8217; them too. Committing the changes that you&amp;#8217;ve racked up tells the version system to store them.&lt;/p&gt;

&lt;p&gt;The pattern is generally to rack up related changes, and then commit them with a message that logs those changes. In the future you can look at those logs and see what changes were made, even over multiple files, because of the way you add them.&lt;/p&gt;

&lt;p&gt;The changes I&amp;#8217;ve added here are simply adding a bare project, so I&amp;#8217;m going to commit them now with a relevant message.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;scm_project $ git commit -m &amp;#39;initial bare rails project&amp;#39;
[master (root-commit) a085392] initial bare rails project
 41 files changed, 8438 insertions(+), 0 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 README
 ...
 create mode 100644 test/performance/browsing_test.rb
 create mode 100644 test/test_helper.rb&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After running the command, notice that git has told me how many insertions and deletions it&amp;#8217;s accomplished. These are line counts. Where are we now? We&amp;#8217;ve added the files we want the version management system to track, we can add more later, and we&amp;#8217;ve committed the first set of changes to those files. Let&amp;#8217;s hope through a few more changes and see what happens.&lt;/p&gt;

&lt;h2 id='making_changes'&gt;Making Changes&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m going to change my application&amp;#8217;s README file.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;scm_project $ echo &amp;#39;My New README&amp;#39; &amp;gt; README
scm_project $ git status
# On branch master
# Changed but not updated:
#   (use &amp;quot;git add &amp;lt;file&amp;gt;...&amp;quot; to update what will be committed)
#   (use &amp;quot;git checkout -- &amp;lt;file&amp;gt;...&amp;quot; to discard changes in working directory)
#
#	modified:   README
#
no changes added to commit (use &amp;quot;git add&amp;quot; and/or &amp;quot;git commit -a&amp;quot;)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our status shows me that I&amp;#8217;ve got changes in the README but I&amp;#8217;ve not added them to a commit. So this highlights an important fact, adding files to git doesn&amp;#8217;t mean &amp;#8216;add the file&amp;#8217; it means &amp;#8216;add the changes&amp;#8217;. Let&amp;#8217;s prove this fact by adding our changed README.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;scm_project $ git add README
scm_project $ git status
# On branch master
# Changes to be committed:
#   (use &amp;quot;git reset HEAD &amp;lt;file&amp;gt;...&amp;quot; to unstage)
#
#	modified:   README
#
scm_project $ git commit -m &amp;#39;showing what modifying files that are tracked does&amp;#39;
[master b9b57e5] showing what modifying files that are tracked does
 1 files changed, 1 insertions(+), 243 deletions(-)
 rewrite README (100%)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our status changed from &amp;#8216;Changed but not updated&amp;#8217; to &amp;#8216;Changes to be committed&amp;#8217;. Changes can be over multiple files and be added in groups, what&amp;#8217;s important is that when you commit those changes they must be relevant to each other. Notice also that git has counted the new lines I&amp;#8217;ve added as well as the ones I deleted. &lt;code&gt;1 files changed, 1 insertions(+), 243 deletions(-)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The pattern I generally follow is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make changes for a feature or bugfix&lt;/li&gt;

&lt;li&gt;Ensure my tests are passing&lt;/li&gt;

&lt;li&gt;Add the changes for that commit&lt;/li&gt;

&lt;li&gt;Commit them as a group describing what I changed overall&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some people like to describe it on a per file basis, but for me it comes down to a feature or bugfix. &amp;#8217;&lt;em&gt;why&lt;/em&gt; did I change it&amp;#8217;, not &amp;#8217;&lt;em&gt;what&lt;/em&gt; did I change&amp;#8217;. This is an important fact to note because the version manager is already logging &amp;#8216;what&amp;#8217; changed, so all that remains is &amp;#8216;why&amp;#8217;.&lt;/p&gt;

&lt;h2 id='looking_at_changes'&gt;Looking at Changes&lt;/h2&gt;

&lt;p&gt;What is it logging? Let&amp;#8217;s take a look:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;scm_project $ git log
2009-08-30 21:15:10 fearoffish ttys001
commit b9b57e53fa0bdcd29b14fb0ded6ab4355ef3cb92
Author: Jamie van Dyke &amp;lt;fearoffish@fearofpro.local&amp;gt;
Date:   Fri Aug 28 23:03:31 2009 +0100

    showing what modifying files that are tracked does

commit a08539202e8bf908106e1736dabf588c3b367151
Author: Jamie van Dyke &amp;lt;fearoffish@fearofpro.local&amp;gt;
Date:   Fri Aug 28 21:58:47 2009 +0100

    initial bare rails project&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What we see is who committed changes, when, and what they logged as the message. You also get a reference id to the commit, which is a 40 character SHA-1 value of the commit contents. When you reference a commit in the future you use this id, like others I mostly just use 6 characters as that&amp;#8217;s more than likely the amount of characters you need to uniquely identify it. The beauty of the @git log@ is that if you keep good logs of the changes you&amp;#8217;ve made and you group your commits correctly, then you can revert blocks of changes as required.&lt;/p&gt;

&lt;h2 id='reverting_changes'&gt;Reverting Changes&lt;/h2&gt;

&lt;p&gt;Let&amp;#8217;s revert the last commit and see how easy it is to go back to previous version of your app.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;scm_project $ git revert b9b57e
2009-08-30 21:20:59 fearoffish ttys001
Finished one revert.
[master 47d2c28] Revert &amp;quot;showing what modifying files that are tracked does&amp;quot;
 1 files changed, 243 insertions(+), 1 deletions(-)
 rewrite README (100%)
scm_project $ git log
2009-08-30 21:33:04 fearoffish ttys001
commit 47d2c28a1c90ed95a32c5e76fa6e669b89ca5f09
Author: Jamie van Dyke &amp;lt;fearoffish@fearofpro.local&amp;gt;
Date:   Sun Aug 30 21:33:03 2009 +0100

    Revert &amp;quot;showing what modifying files that are tracked does&amp;quot;

    This reverts commit b9b57e53fa0bdcd29b14fb0ded6ab4355ef3cb92.

commit b9b57e53fa0bdcd29b14fb0ded6ab4355ef3cb92
Author: Jamie van Dyke &amp;lt;fearoffish@fearofpro.local&amp;gt;
Date:   Fri Aug 28 23:03:31 2009 +0100

    showing what modifying files that are tracked does

commit a08539202e8bf908106e1736dabf588c3b367151
Author: Jamie van Dyke &amp;lt;fearoffish@fearofpro.local&amp;gt;
Date:   Fri Aug 28 21:58:47 2009 +0100

    initial bare rails project&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you run the git revert command, you give it the SHA-1 reference &amp;#8211; or six characters, like I did &amp;#8211; and git will remove any changes you made for that commit. Cool, huh? So you are keeping multiple versions of your application without keeping multiple files.&lt;/p&gt;

&lt;p&gt;Okay, that&amp;#8217;s enough for this episode. I&amp;#8217;ll be creating more episodes on subjects like local and remote repositories, hosting your Rails applications and more, soon.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=KUWf3pw_WVA:cMZWTCkII58:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=KUWf3pw_WVA:cMZWTCkII58:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=KUWf3pw_WVA:cMZWTCkII58:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=KUWf3pw_WVA:cMZWTCkII58:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=KUWf3pw_WVA:cMZWTCkII58:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=KUWf3pw_WVA:cMZWTCkII58:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=KUWf3pw_WVA:cMZWTCkII58:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=KUWf3pw_WVA:cMZWTCkII58:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=KUWf3pw_WVA:cMZWTCkII58:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=KUWf3pw_WVA:cMZWTCkII58:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FearOfFish-RubyOnRails/~4/KUWf3pw_WVA" height="1" width="1"/&gt;</content>
    <published>2009-08-30T20:39:41+01:00</published>
  <feedburner:origLink>http://www.jamievandyke.com/web-development-with-source-code-management-a-basic-guide</feedburner:origLink></entry>
  <entry>
    <title>Giving Twitter some WoW</title>
    <link type="text/html" href="http://feedproxy.google.com/~r/FearOfFish-RubyOnRails/~3/X3mGWzV_SWw/twitter-world-of-warcraft-announcements" rel="alternate" />
    <id>tag:www.jamievandyke.com,2009-05-03:/twitter-world-of-warcraft-announcements</id>
    <content type="html">&lt;p&gt;It&amp;#8217;s been a while since I posted anything, and I intend to fix that with smaller posts that describe things I&amp;#8217;m doing. So let&amp;#8217;s start off this new regime with a little post about a tiny script I wrote the other day for my WoW guild. We are now using a twitter account to post scheduled raids and other announcements, and I knocked together a little script that parses our guilds (Enigma on Hellfire) guildomatic site for raids we&amp;#8217;ve rostered for later that day, and it posts them to twitter.&lt;/p&gt;

&lt;p&gt;I needed to parse some html and for that I use the venerable &lt;a href='http://wiki.github.com/why/hpricot'&gt;HPricot&lt;/a&gt; gem, and to communicate with &lt;a href='http://www.twitter.com/'&gt;Twitter&lt;/a&gt; I use the &lt;a href='http://twitter.rubyforge.org/'&gt;Twitter gem&lt;/a&gt;. Here&amp;#8217;s the code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require &amp;#39;rubygems&amp;#39;
require &amp;#39;twitter&amp;#39;
require &amp;#39;hpricot&amp;#39;  
require &amp;#39;open-uri&amp;#39;  
require &amp;#39;parsedate&amp;#39;

TWITTER_USERNAME = &amp;#39;replaceme&amp;#39;
TWITTER_PASSWORD = &amp;#39;replaceme&amp;#39;
# http://enigma-hellfire.guildomatic.com/ is ours
GUILD_SITE = &amp;#39;replaceme&amp;#39;

def get_raids(doc)  
  message = &amp;quot;[RAID REMINDER] &amp;quot;
  curr_date = Time.new
  raids_today = false
  (doc/&amp;quot;tr.today&amp;quot;).each do |post|
    raids_today = true
    (post/&amp;quot;td.clickable/a&amp;quot;).each do |name|
      unless name.inner_html.include?( &amp;#39;Roster&amp;#39; ) or name.inner_html.include?( &amp;#39;roster&amp;#39; )
        message &amp;lt;&amp;lt; name.inner_html 
        (post/&amp;quot;td.inviteAtTime&amp;quot;).each do |start_time|
          message &amp;lt;&amp;lt; &amp;quot; (&amp;quot; &amp;lt;&amp;lt; start_time.inner_html &amp;lt;&amp;lt; &amp;quot;) | &amp;quot;
        end
      end
    end
  end
  raids_today ? message[0..-3] : nil
end  

doc = Hpricot(open(GUILD_SITE))  

httpauth = Twitter::HTTPAuth.new(TWITTER_USERNAME, TWITTER_PASSWORD)
base = Twitter::Base.new(httpauth)
message = get_raids(doc)

if message
  base.update(message)
else
  base.update(&amp;quot;[RAID REMINDER] There are no raids today, take a break, slacker!&amp;quot;)
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Guildomatic has the raids for today posted in a table cell with a class of &amp;#8216;today&amp;#8217;, which made this much easier. You get the idea from the code.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m also cheered up immensely on what 10 minutes of key bashing can output. I run this on my server (hosted by &lt;a href='http://www.linode.com/'&gt;Linode&lt;/a&gt;) in a cron job at 12pm every day.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=X3mGWzV_SWw:XP22NjOdVKI:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=X3mGWzV_SWw:XP22NjOdVKI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=X3mGWzV_SWw:XP22NjOdVKI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=X3mGWzV_SWw:XP22NjOdVKI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=X3mGWzV_SWw:XP22NjOdVKI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=X3mGWzV_SWw:XP22NjOdVKI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=X3mGWzV_SWw:XP22NjOdVKI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=X3mGWzV_SWw:XP22NjOdVKI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=X3mGWzV_SWw:XP22NjOdVKI:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=X3mGWzV_SWw:XP22NjOdVKI:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FearOfFish-RubyOnRails/~4/X3mGWzV_SWw" height="1" width="1"/&gt;</content>
    <published>2009-05-03T19:25:44+01:00</published>
  <feedburner:origLink>http://www.jamievandyke.com/twitter-world-of-warcraft-announcements</feedburner:origLink></entry>
  <entry>
    <title>My PDF Ruby on Rails Beginner Handout</title>
    <link type="text/html" href="http://feedproxy.google.com/~r/FearOfFish-RubyOnRails/~3/uhE6ugN92vQ/ruby-on-rails-handout" rel="alternate" />
    <id>tag:www.jamievandyke.com,2008-12-09:/ruby-on-rails-handout</id>
    <content type="html">&lt;p&gt;A while ago I gave away my Ruby on Rails handout for beginners. It was a PDF that contained the real basics for getting started or at least understanding the fundamentals of what &lt;a href='http://www.rubyonrails.org/'&gt;Ruby on Rails&lt;/a&gt; is all about. However, my blog changed, the article url moved and ultimately it disappeared.&lt;/p&gt;

&lt;p&gt;Well here it is again, there are plenty of books like this out there, but hopefully there&amp;#8217;s something in it that will help you start.&lt;/p&gt;

&lt;p&gt;For now, here&amp;#8217;s the &lt;a href='http://s3.amazonaws.com/jamievandyke-blog-assets/fearoffish_ruby_on_rails_handout.pdf'&gt;Ruby on Rails Beginner Handout&lt;/a&gt; again.&lt;/p&gt;
&lt;a href='http://s3.amazonaws.com/jamievandyke-blog-assets/fearoffish_ruby_on_rails_handout.pdf' title='Ruby on Rails Beginner handout'&gt;
  &lt;img src='/attachments/handout_screenshot.png' alt='Ruby on Rails Beginner Handout Screenshot' width='300px' /&gt;
&lt;/a&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=uhE6ugN92vQ:gGjyMHT6iYY:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=uhE6ugN92vQ:gGjyMHT6iYY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=uhE6ugN92vQ:gGjyMHT6iYY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=uhE6ugN92vQ:gGjyMHT6iYY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=uhE6ugN92vQ:gGjyMHT6iYY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=uhE6ugN92vQ:gGjyMHT6iYY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=uhE6ugN92vQ:gGjyMHT6iYY:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=uhE6ugN92vQ:gGjyMHT6iYY:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?a=uhE6ugN92vQ:gGjyMHT6iYY:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/FearOfFish-RubyOnRails?i=uhE6ugN92vQ:gGjyMHT6iYY:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FearOfFish-RubyOnRails/~4/uhE6ugN92vQ" height="1" width="1"/&gt;</content>
    <published>2008-12-09T22:32:48+00:00</published>
  <feedburner:origLink>http://www.jamievandyke.com/ruby-on-rails-handout</feedburner:origLink></entry>
</feed>

