<?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" xml:lang="en-US">
  <id>tag:capturedsparks.com:entries</id>
  <link type="text/html" href="http://capturedsparks.com" rel="alternate" />
  <title>captured sparks</title>
  <updated>2008-02-07T22:38:27+00:00</updated>
  <link rel="self" href="http://feeds.feedburner.com/capturedsparks" type="application/atom+xml" /><entry>
    <id>tag:capturedsparks.com:Entry1</id>
    <published>2008-02-07T22:38:27+00:00</published>
    <updated>2008-05-18T16:16:40+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/1-welcome-to-captured-sparks" rel="alternate" />
    <title>Welcome to captured sparks</title>
    <content type="html">&lt;p&gt;This inaugural post comes after several days of arguing with Ubuntu, Apache and Mongrel.&lt;/p&gt;
&lt;p&gt;This site is hosted on a 256 slice from &lt;a href="http://www.slicehost.com/"&gt;Slicehost&lt;/a&gt; and I&amp;#8217;ve learnt a lot about Apache configuration, working with Linux and am now intimately familiar with the command line.&lt;/p&gt;
&lt;p&gt;During the process, I&amp;#8217;ve been helped by a significant number of resources that are out there and I intend to run a series of posts on how I got this site up and running in the hope that I may &lt;a href="http://blog.codahale.com/2006/06/19/time-for-a-grown-up-server-rails-mongrel-apache-capistrano-and-you/"&gt;stand on the shoulders of giants&lt;/a&gt; and provide some insight of my own.&lt;/p&gt;
&lt;p&gt;As a side note, you might have seen that this site is running on &amp;#8220;sparky&amp;#8221;.  This is a custom built &lt;span class="caps"&gt;CMS&lt;/span&gt; coded in Rails that is very much in version 0.1.  I&amp;#8217;ll be doing some posts on its development as well as walking through some features as I add them.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry2</id>
    <published>2008-02-08T08:36:42+00:00</published>
    <updated>2008-05-18T16:16:40+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/2-heroku" rel="alternate" />
    <title>Heroku</title>
    <content type="html">&lt;p&gt;Would I have swapped the struggles of the last few days in terms of getting this up and running for the simplicity of &lt;a href="http://heroku.com/"&gt;Heroku&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not sure that I would.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry3</id>
    <published>2008-02-08T22:12:23+00:00</published>
    <updated>2008-05-18T16:16:40+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/3-attachment-fu-where-are-the-images-" rel="alternate" />
    <title>attachment_fu - where are the images?</title>
    <content type="html">&lt;p&gt;It occurred to me late last night that due to my use of Capistrano to deploy sparky, any images that were uploaded were getting lost every time I deployed.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href="http://www.almosteffortless.com/2007/03/25/working-with-attachment_fu/"&gt;a great article at almost effortless&lt;/a&gt;, I thought I had the problem solved.&lt;/p&gt;
&lt;p&gt;Unfortunately, attachment_fu seems insistent on adding leading slashes, leading directories and all manner of things to the public_filename path.  As such, all my images have disappeared until such time as I can fix this.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry4</id>
    <published>2008-02-09T08:18:48+00:00</published>
    <updated>2008-05-18T16:16:40+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/4-attachment-fu-problem-fixed" rel="alternate" />
    <title>attachment_fu problem fixed</title>
    <content type="html">&lt;p&gt;Just as I shut the laptop last night to go to bed, I came up with a solution to my leading slash problem.&lt;/p&gt;
&lt;p&gt;attachment_fu&amp;#8217;s default behaviour is to partition the directories into which it stores files based on id.  In my case, my images were being placed into the folder public/images/0000/#{id}.&lt;/p&gt;
&lt;p&gt;As such, I amended my deploy.rb file to read:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;task &lt;span class="sy"&gt;:after_update_code&lt;/span&gt;, &lt;span class="sy"&gt;:roles&lt;/span&gt; =&amp;amp;gt; &lt;span class="sy"&gt;:app&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  %w{0000}.each do |share|&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    run &amp;amp;&lt;span class="c"&gt;#8220;rm -rf #{release_path}/public/images/#{share}&amp;amp;#8221;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    run &amp;amp;&lt;span class="c"&gt;#8220;mkdir -p #{shared_path}/system/images/#{share}&amp;amp;#8221;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    run &amp;amp;&lt;span class="c"&gt;#8220;ln -s #{shared_path}/system/images/#{share} #{release_path}/public/images/#{share}&amp;amp;#8221;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;This symlinked the 0000 directory to an identically named directory in the shared part of the system.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve deployed a couple of times since then and my images are still accessible.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry5</id>
    <published>2008-02-10T14:33:07+00:00</published>
    <updated>2008-05-18T16:16:40+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/5-integrating-google-shared-items-with-rails" rel="alternate" />
    <title>Integrating Google Shared Items with Rails</title>
    <content type="html">&lt;p&gt;As part of the home page on captured sparks, I wanted to have a &amp;#8220;Recent Reads&amp;#8221; section where I could list the articles that have caught my attention recently.  I do most of my reading in Google Reader and thought that the Shared Items feature in Reader would be perfect for this.  Thanks to the FeedTools gem, adding this was straightforward.&lt;/p&gt;
&lt;p&gt;Firstly, grab the FeedTools gem, using sudo if necessary:&lt;/p&gt;
&lt;pre&gt;gem install feedtools&lt;/pre&gt;
&lt;p&gt;The way I added this function was to use a helper method inside my home_helper.rb call shared_items.  Firstly require the gem in the head of the helper:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;gem &amp;amp;&lt;span class="c"&gt;#8216;feedtools&amp;amp;#8217;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &amp;amp;&lt;span class="c"&gt;#8216;feed_tools&amp;amp;#8217;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;Next, set up some variables that we will use throughout the method:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;&lt;pre&gt;content&lt;/pre&gt;&lt;/dt&gt;
&lt;dd&gt;will be used to contain our shared items&lt;/dd&gt;
&lt;dt&gt;&lt;pre&gt;days&lt;/pre&gt;&lt;/dt&gt;
&lt;dd&gt;used to calculate how old the oldest shared item will be&lt;/dd&gt;
&lt;dt&gt;&lt;pre&gt;time&lt;/pre&gt;&lt;/dt&gt;
&lt;dd&gt;used to make sure each entry is not too old&lt;/dd&gt;
&lt;dt&gt;&lt;pre&gt;share_url&lt;/pre&gt;&lt;/dt&gt;
&lt;dd&gt;the &lt;span class="caps"&gt;RSS&lt;/span&gt; feed for the shared items&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Setting up the method now looks like:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;content = &amp;amp;&lt;span class="c"&gt;#8216;&amp;amp;#8217;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;days = &lt;span class="i"&gt;15&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;time = Time.now.utc &amp;amp;#8211; (86400 * days.to_i)&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;share_url = &amp;amp;&lt;span class="c"&gt;#8217;http://www.google.com/reader/public/atom/user/13411963057092720812/state/com.google/broadcast&amp;amp;#8217;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;To create the shared item list:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;feed = &lt;span class="co"&gt;FeedTools&lt;/span&gt;::&lt;span class="co"&gt;Feed&lt;/span&gt;.open(share_url)&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  feed.entries.each do |entry|&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; entry.published &amp;amp;gt; time&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;      content &amp;amp;lt;&amp;amp;lt; &amp;amp;quot; &amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="k"&gt;&amp;amp;quot;&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;      content &amp;amp;lt;&amp;amp;lt; &amp;amp;quot; &amp;lt;a href=&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;#{entry.link}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;span class="c"&gt;#{entry.title}&amp;lt;/a&amp;gt;\n&amp;amp;quot;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      content &amp;amp;lt;&amp;amp;lt; &amp;amp;quot; &amp;lt;p &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;entry.find_node(&amp;amp;&lt;span class="c"&gt;#8220;source/title/text()&amp;amp;#8221;).to_s}\n&amp;amp;quot;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      content &amp;amp;lt;&amp;amp;lt; &amp;amp;quot; &amp;lt;&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;li&amp;gt;&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="k"&gt;&amp;amp;quot;&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;Finally, check to see if anything is shared and add the appropriate &lt;span class="caps"&gt;HTML&lt;/span&gt; container (or witty comment if nothing is shared), then return the content.&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;if&lt;/span&gt; content.length &amp;amp;gt; &lt;span class="i"&gt;0&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  content = &amp;amp;#8220;&amp;lt;ul&amp;gt;&amp;amp;#8221; + content&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  content &amp;amp;lt;&amp;amp;lt; &amp;amp;&lt;span class="c"&gt;#8220;&amp;lt;/ul&amp;gt;\n&amp;amp;#8221;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;else&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  content = &amp;amp;#8220;&amp;lt;p &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;span class="co"&gt;Not&lt;/span&gt; read anything of interest recently.&amp;amp;&lt;span class="c"&gt;#8221;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;return content&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;The helper method is then called in the view by simply adding:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;amp;lt;&lt;span class="s"&gt;&lt;span class="dl"&gt;%=&lt;/span&gt;&lt;span class="k"&gt; shared_items %&amp;amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
You can read more about FeedTools in the &lt;a href="http://feedtools.rubyforge.org/"&gt;FeedTools &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt;.</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry6</id>
    <published>2008-02-10T19:31:41+00:00</published>
    <updated>2008-05-18T16:16:40+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/6-of-we-and-i" rel="alternate" />
    <title>Of We and I</title>
    <content type="html">&lt;p&gt;Having worked in a multi-national corporate for the last 6 years, it is common practice for me to refer to a company as &amp;#8220;we&amp;#8221;. You may have noticed that I use &amp;#8220;we&amp;#8221; when talking about captured sparks on this site. The headline on the homepage is &amp;#8220;We can make your website sparkle&amp;#8221;.&lt;/p&gt;
&lt;p&gt;We, in the case of captured sparks, is me. It is I. One person.&lt;/p&gt;
&lt;p&gt;Should it ever get to the stage where other people come on board, I&amp;#8217;ll let you know. Until then, it&amp;#8217;s just me.  Even when I say &amp;#8220;we&amp;#8221;.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry7</id>
    <published>2008-02-12T10:45:11+00:00</published>
    <updated>2008-05-18T16:16:40+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/7-using-self-in-ruby" rel="alternate" />
    <title>Using self in Ruby</title>
    <content type="html">&lt;p&gt;One of the things that had me confused early on when programming in Ruby was when to use &amp;#8220;self&amp;#8221; for a method and when not to.&lt;/p&gt;
&lt;p&gt;The easiest way to summarise, I think, is to say that &lt;pre&gt;self.method&lt;/pre&gt; should be used when referring to a method that operates on the class itself.  &lt;pre&gt;method&lt;/pre&gt; should be used when referring to a method that operates on an instance of the class.&lt;/p&gt;
&lt;p&gt;The most common place this is seen in Rails application is in authentication systems.  The method for logging a user into an application is usually written as:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="co"&gt;Class&lt;/span&gt; &lt;span class="co"&gt;User&lt;/span&gt; &amp;amp;lt; &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&amp;lt;&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;p&amp;gt;&lt;tt&gt;
&lt;/tt&gt;def self.authenticate(user, password)&lt;tt&gt;
&lt;/tt&gt;&amp;amp;#8230;&lt;tt&gt;
&lt;/tt&gt;end&lt;tt&gt;
&lt;/tt&gt;&amp;lt;p&amp;gt;end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;This is then called in the controller as:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="co"&gt;Class&lt;/span&gt; &lt;span class="co"&gt;SessionsController&lt;/span&gt; &amp;amp;lt; &lt;span class="co"&gt;ActionController&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&amp;lt;&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;p&amp;gt;&lt;tt&gt;
&lt;/tt&gt;def new&lt;tt&gt;
&lt;/tt&gt;@user = User.authenticate(params[:session])&lt;tt&gt;
&lt;/tt&gt;end&lt;tt&gt;
&lt;/tt&gt;&amp;lt;p&amp;gt;end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;In contrast, methods can then be called on the @user object once the user has logged in.  For example, to check if the user is an administrator, the following method could be used in our User class:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;is_admin?&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;amp;#8230;&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;This could then be called within the view, perhaps to display certain restricted information:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&amp;amp;lt;&lt;span class="s"&gt;&lt;span class="dl"&gt;%=&lt;/span&gt;&lt;span class="k"&gt; if @user.is_admin? %&amp;amp;gt;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;As a complete aside, I love how the above code demonstrates the readability of Ruby.  There is no doubt as to what that statement means.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry8</id>
    <published>2008-02-12T11:38:05+00:00</published>
    <updated>2008-05-18T16:16:40+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/8-uk-to-ban-filesharers-from-the-net-" rel="alternate" />
    <title>UK to ban filesharers from the net?</title>
    <content type="html">&lt;p&gt;A &lt;a href="http://technology.timesonline.co.uk/tol/news/tech_and_web/the_web/article3353387.ece"&gt;report in the Times&lt;/a&gt; this morning is getting a lot of coverage.  It states that the UK government intends to legislate to require ISPs to take action against individuals using their networks for file-sharing activities.&lt;/p&gt;
&lt;p&gt;Quite how the government expects ISPs to monitor every bit of traffic that passes through their network is anyone&amp;#8217;s guess.  It is again indicative of the music industry&amp;#8217;s insistence on spending their money on lobbying for legislation to protect a failing business model, rather than adapting to the changing face of music.&lt;/p&gt;
&lt;p&gt;Becky Hogge of the &lt;a href="http://www.openrightsgroup.org"&gt;Open Rights Group&lt;/a&gt; (an organisation for which I volunteer) is appearing opposite the &lt;span class="caps"&gt;BPI&lt;/span&gt; on Radio 4&amp;#8217;s World at One to discuss the story.  &lt;span class="caps"&gt;ORG&lt;/span&gt; will no doubt be responding to any future consultation.&lt;/p&gt;
&lt;p&gt;For further reading on the story, I recommend &lt;a href="http://uk.techcrunch.com/2008/02/12/the-sheer-craven-stupidity-of-government-regulation-of-online-music"&gt;Techcrunch UK&lt;/a&gt;, &lt;a href="http://www.techcrunch.com/2008/02/12/uk-proposes-three-strikes-and-your-out-illegal-downloading-law/"&gt;Techcrunch&lt;/a&gt;, the &lt;a href="http://www.techdirt.com/articles/20080211/220305233.shtml"&gt;always excellent Techdirt&lt;/a&gt; and &lt;a href="http://www.bbc.co.uk/blogs/technology/2008/02/uk_takes_tough_stance_on_pirac.html"&gt;&lt;span class="caps"&gt;BBC&lt;/span&gt; News&amp;#8217; Darren Waters&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;: &lt;span class="caps"&gt;ORG&lt;/span&gt; have &lt;a href="http://www.openrightsgroup.org/2008/02/12/government-to-ban-illegal-filesharers-from-the-internet/"&gt;a post about this story&lt;/a&gt;.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry9</id>
    <published>2008-02-13T12:52:46+00:00</published>
    <updated>2008-05-18T16:16:40+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/9-custom-spam-prevention" rel="alternate" />
    <title>Custom spam prevention</title>
    <content type="html">&lt;p&gt;Inspired by &lt;a href="http://www.snook.ca/archives/other/effective_blog_comment_spam_blocker"&gt;Jonathan&lt;/a&gt;, I spent some time last night working on spam prevention for the comments here at captured sparks.  I had seen a good article on integrating Akismet with Rails but as this is a home-baked &lt;span class="caps"&gt;CMS&lt;/span&gt;, and having read &lt;a href="http://www.snook.ca/archives/other/effective_blog_comment_spam_blocker"&gt;Jonathan&amp;#8217;s approach to the issue&lt;/a&gt; decided to have a go myself.&lt;/p&gt;
&lt;p&gt;I adopted a similar approach to Jonathan of assigning a score to a comment and then either automatically posting the comment or holding it back for approval .  The validation is handled by a before_create callback in the comment model.  Here&amp;#8217;s an extract of the validation method:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;body = &lt;span class="pc"&gt;self&lt;/span&gt;.body&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;amp;#8230;&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;score -= body.scan(&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;viagra&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;).size&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;amp;#8230;&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;case&lt;/span&gt; score&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;when 1..999&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt; write_attribute(&lt;span class="sy"&gt;:approved&lt;/span&gt;, &lt;span class="pc"&gt;true&lt;/span&gt;)&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;amp;#8230;&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;At the moment, the validation is very basic and leans towards a cautious approach to automatic posting.  Having said that, all comments are saved to the database for review.  I&amp;#8217;m not content enough to start automatically rejecting the comments yet.&lt;/p&gt;
&lt;p&gt;Thank to Jonathan for the inspiration.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry10</id>
    <published>2008-02-15T08:51:17+00:00</published>
    <updated>2008-05-18T16:16:40+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/10-blogging-the-building-of-your-app" rel="alternate" />
    <title>Blogging the building of your app</title>
    <content type="html">&lt;p&gt;One to watch over at &lt;a href="http://nextupdate.com/"&gt;Next Update&lt;/a&gt;, where they are blogging the building of their issue and bug tracking app.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry11</id>
    <published>2008-02-16T08:55:12+00:00</published>
    <updated>2008-05-18T16:16:41+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/11-everyone-should-have-a-web-app" rel="alternate" />
    <title>Everyone should have a web app</title>
    <content type="html">&lt;p&gt;I&amp;#8217;ve come up with a little idea for a web app.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s going to be for a niche market where the current solutions to the issue are enterprise level with a huge server licence and slightly-less-huge user licences. There is a lot of competition for the traditional solution but none for a simple, hosted solution.&lt;/p&gt;
&lt;p&gt;The market I am targeting is historically very traditional and this may present a small barrier to adoption but this is for the sector in which I currently work and &lt;em&gt;I&lt;/em&gt; know that &lt;em&gt;I&lt;/em&gt; would want something like this.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not going to come as a shock to say that I admire &lt;a href="http://www.37signals.com"&gt;37 Signals&lt;/a&gt; (who doesn&amp;#8217;t?). Part of their ethos though is to build what you know and what you use. That way, there is less chance of &lt;a href="http://en.wikipedia.org/wiki/Creeping_featurism"&gt;featuritis&lt;/a&gt;. And I know exactly what this app should do.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry12</id>
    <published>2008-02-18T12:26:33+00:00</published>
    <updated>2008-05-18T16:16:41+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/12-the-cool-stuff-has-to-wait" rel="alternate" />
    <title>The cool stuff has to wait</title>
    <content type="html">&lt;p&gt;As I sit here, all sorts of ideas are popping into my head that would be awesome to implement for my upcoming app.  Unfortunately, they need to go on the back-burner.&lt;/p&gt;
&lt;p&gt;I started work on the app yesterday afternoon and am still in the process of creating my models and controllers to give a basic functionality.  Whilst I do enjoy working in Rails, this is the boring bit.  I can&amp;#8217;t wait until I can really get into creating my own methods and putting some of these ideas into practice.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry13</id>
    <published>2008-02-22T10:53:10+00:00</published>
    <updated>2008-05-18T16:16:41+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/13-the-need-to-know-ruby" rel="alternate" />
    <title>The need to know Ruby</title>
    <content type="html">&lt;p&gt;As part of the development of my app, I had a need to display various different categories of to-do items &amp;#8211; complete, overdue and &amp;#8220;normal&amp;#8221;.&lt;/p&gt;
&lt;p&gt;I was using a method in the Todo class similar to the following to create these categories:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.find_overdue&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  overdue = Array.new&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  items = find(&lt;span class="sy"&gt;:all&lt;/span&gt;)&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  for item in items&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;if&lt;/span&gt; item.overdue?&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;      overdue &amp;amp;lt;&amp;amp;lt; item&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;else&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  overdue&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;I was reading through the online Ruby documentation on another issue and came across a nice method in the Hash class: reject.  This acts as a &amp;#8220;delete if&amp;#8221; method and can substantially reduce the code above:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.find_overdue&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  items = find(:all)&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  items.reject { |i| i.not_overdue? }&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;The &amp;#8220;not_overdue&amp;#8221; method is defined separately in the Todo class.  I think this definitely shows the importance of knowing the Ruby language and equally demonstrates its power.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry14</id>
    <published>2008-02-25T21:59:30+00:00</published>
    <updated>2008-05-18T16:16:41+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/14-dynamically-generating-a-sitemap-for-google" rel="alternate" />
    <title>Dynamically generating a sitemap for Google</title>
    <content type="html">&lt;p&gt;One of the issues I encountered with my previous Rails application was adding a sitemap to the root directory so that I could use &lt;a href="http://www.google.com/webmasters/tools"&gt;Google&amp;#8217;s Webmaster Tools&lt;/a&gt;. As I was not under a deadline for sparky, I was able to dedicate some time to the issue.&lt;/p&gt;
&lt;p&gt;I figured the easiest way to create the sitemap was to use Rails&amp;#8217; built-in &lt;span class="caps"&gt;XML&lt;/span&gt; builder to dynamically generate the sitemap when requested by Google.  This has the advantage of picking up every new blog entry.&lt;/p&gt;
&lt;p&gt;First was the controller.  In order to keep everything segregated and RESTful, I created a sitemaps controller with one action:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;SitemapController&lt;/span&gt; &amp;amp;lt; &lt;span class="co"&gt;ApplicationController&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;sitemap&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    @entries = Entry.find(:all)&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@jobs&lt;/span&gt; = &lt;span class="co"&gt;Job&lt;/span&gt;.find(&lt;span class="sy"&gt;:all&lt;/span&gt;)&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    &amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    respond_to &lt;span class="r"&gt;do&lt;/span&gt; |format|&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;      format.xml { render :layout =&amp;amp;gt; false }&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;I retrieve all the dynamic information in the controller, which is then passed to the view file.  Creating the view was a lot of trial and error, particularly in terms of getting it to match the sitemap specification.  Here though is the final view file split into chunks for commentary purposes.&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;base_url = &amp;amp;&lt;span class="c"&gt;#8220;http://www.capturedsparks.com&amp;amp;#8221;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;xml.instruct! &lt;span class="sy"&gt;:xml&lt;/span&gt;, &lt;span class="sy"&gt;:version=&lt;/span&gt;&amp;amp;gt;&amp;amp;quot;&lt;span class="fl"&gt;1.0&lt;/span&gt;&amp;amp;quot;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;xml.tag! &amp;amp;#8216;urlset&amp;amp;#8217;, &amp;amp;#8220;xmlns&amp;amp;#8221; =&amp;amp;gt; &amp;amp;#8220;http:&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;/www.sitemaps.org/schemas/sitemap/&lt;span class="fl"&gt;0.9&lt;/span&gt;&amp;amp;&lt;span class="c"&gt;#8221; do&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;This sets the header information in the resulting xml file as required by the sitemap specification.&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;for&lt;/span&gt; entry &lt;span class="r"&gt;in&lt;/span&gt; &lt;span class="iv"&gt;@entries&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  xml.tag! &amp;amp;#8216;url&amp;amp;#8217; do&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    xml.tag! &amp;amp;&lt;span class="c"&gt;#8216;loc&amp;amp;#8217;, &amp;amp;#8220;#{base_url}#{generate_url(entry)}&amp;amp;#8221;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    xml.tag! &amp;amp;&lt;span class="c"&gt;#8216;lastmod&amp;amp;#8217;, entry.updated_at.strftime(&amp;amp;#8220;%Y-%m-%d&amp;amp;#8221;)&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    xml.tag! &amp;amp;&lt;span class="c"&gt;#8216;changefreq&amp;amp;#8217;, &amp;amp;#8216;monthly&amp;amp;#8217;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    xml.tag! &amp;amp;&lt;span class="c"&gt;#8216;priority&amp;amp;#8217;, &amp;amp;#8216;0.8&amp;amp;#8217;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;This iterates through the blog entries, which are contained in the @entries variable set in the controller.  This is then followed with identical code for the @jobs variable.&lt;/p&gt;
&lt;p&gt;For each of the static pages (including the blog and job indexes), I use the following code assigning them higher priorities than the individual blog and job entries.&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;xml.tag! &amp;amp;&lt;span class="c"&gt;#8216;url&amp;amp;#8217; do&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    xml.tag! &amp;amp;&lt;span class="c"&gt;#8216;loc&amp;amp;#8217;, &amp;amp;#8220;http://www.capturedsparks.com/about/&amp;amp;#8221;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    xml.tag! &amp;amp;&lt;span class="c"&gt;#8216;changefreq&amp;amp;#8217;, &amp;amp;#8216;monthly&amp;amp;#8217;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    xml.tag! &amp;amp;&lt;span class="c"&gt;#8216;priority&amp;amp;#8217;, &amp;amp;#8216;1&amp;amp;#8217;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;The resulting xml file can be seen &lt;a href="http://www.capturedsparks.com/sitemap.xml"&gt;here&lt;/a&gt;.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry15</id>
    <published>2008-02-25T22:35:11+00:00</published>
    <updated>2008-05-18T16:16:41+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/15-about-the-sidebar" rel="alternate" />
    <title>About the sidebar</title>
    <content type="html">&lt;p&gt;I&amp;#8217;ve add a sidebar to the individual blog entry pages so that I can let visitors know that we do some web design.&lt;/p&gt;
&lt;p&gt;Just to confirm that I haven&amp;#8217;t left off my ruby output tags.  The idea of using variable names was inspired by &lt;a href="http://wilwheaton.typepad.com/"&gt;Wil Wheaton&lt;/a&gt; and the auto-responder he used to have.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry16</id>
    <published>2008-02-28T21:34:08+00:00</published>
    <updated>2008-05-18T16:16:41+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/16-creating-monthly-archives-in-rails" rel="alternate" />
    <title>Creating monthly archives in Rails</title>
    <content type="html">&lt;p&gt;Whilst creating my own blog software has made me realise how little I needed compared to the vast functionality of readily-available software, one of the things I did want was a monthly archive view.&lt;/p&gt;
&lt;p&gt;The first thing I did was create a method in the Entry model that would assign each entry an &amp;#8220;archive link&amp;#8221; consisting of the month and year in which the entry was created:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Entry&lt;/span&gt; &amp;amp;lt; &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;&amp;lt;&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;p&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;lt;p&amp;gt;after_create :create_archive_link&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;amp;&lt;span class="c"&gt;#8230;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;create_archive_link&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  month = self.created_at.strftime(&amp;amp;#8220;%B %Y&amp;amp;#8221;)&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  month = month.downcase.sub(&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;[ ]&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;, &amp;amp;quot;&amp;amp;quot;)&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  self.month_year = month&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="pc"&gt;self&lt;/span&gt;.save&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;I have to confess at this point that I broke from the RESTful conventions that I try to employ and created a monthly_index method in the entries controller:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;monthly_index&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  @entries = Entry.find_all_by_month_year(params[:month])&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="iv"&gt;@entry&lt;/span&gt; = &lt;span class="iv"&gt;@entries&lt;/span&gt;&amp;lt;sup &lt;span class="r"&gt;class&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;footnote&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;a href=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;#fn1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;span class="i"&gt;1&lt;/span&gt;&amp;lt;&lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;a&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="mod"&gt;su&lt;/span&gt;&lt;/span&gt;p&amp;gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  @all_entries = Entry.find(:all)&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;For the blog index, I then list the monthly archives using the following code:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="ta"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="en"&gt;&amp;amp;lt;&lt;/span&gt;% @all_entries.group_by(&lt;span class="en"&gt;&amp;amp;amp;&lt;/span&gt;:month_year).each do |month, entries| %&lt;span class="en"&gt;&amp;amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="ta"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="en"&gt;&amp;amp;lt;&lt;/span&gt;%= link_to &lt;span class="en"&gt;&amp;amp;#8220;&lt;/span&gt;#{month} (#{entries.size})&lt;span class="en"&gt;&amp;amp;#8221;&lt;/span&gt;, monthly_archive_url(month.downcase.sub(/[ ]/, &lt;span class="en"&gt;&amp;amp;quot;&lt;/span&gt;&lt;span class="en"&gt;&amp;amp;quot;&lt;/span&gt;)) %&lt;span class="en"&gt;&amp;amp;gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="en"&gt;&amp;amp;lt;&lt;/span&gt;% end %&lt;span class="en"&gt;&amp;amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;This code does several things in a short space of time:&lt;/p&gt;
&lt;p&gt;1) Groups each entry by a defined month_year method resulting in a hash keyed on the month_year method&lt;/p&gt;
&lt;p&gt;2) Prepares to iterate through the hash based on the month_year key&lt;/p&gt;
&lt;p&gt;3) Lists the month name and the number of posts in that month with a link to a monthly_archive_url route that is defined in routes.rb&lt;/p&gt;
&lt;p&gt;In routes.rb, the following route is defined:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="co"&gt;ActionController&lt;/span&gt;::&lt;span class="co"&gt;Routing&lt;/span&gt;::&lt;span class="co"&gt;Routes&lt;/span&gt;.draw &lt;span class="r"&gt;do&lt;/span&gt; |map|&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&amp;amp;#8230;&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  map.monthly_archive &amp;amp;&lt;span class="c"&gt;#8216;entries/archive/:month&amp;amp;#8217;, :controller =&amp;amp;gt; &amp;amp;#8216;entries&amp;amp;#8217;, :action =&amp;amp;gt; &amp;amp;#8216;monthly_index&amp;amp;#8217;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&amp;amp;&lt;span class="c"&gt;#8230;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;I think the code could be cleaned up a little bit by defining more methods in the model.  Just writing this has made me think that I should define a method to convert the archive link of february2008 back into February 2008.&lt;/p&gt;
&lt;p&gt;What I have found is that writing a lot of the code needed to run an effective blogging platform is not particularly complicated when the function needed is broken down into a series of steps.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry17</id>
    <published>2008-03-02T19:08:40+00:00</published>
    <updated>2008-05-18T16:16:41+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/17-a-little-bit-on-growl-and-autotest" rel="alternate" />
    <title>A little bit on growl and Autotest</title>
    <content type="html">&lt;p&gt;There&amp;#8217;s not a lot that I can say that hasn&amp;#8217;t been said already on this subject.  I&amp;#8217;ve managed to get this working tonight via a combination of &lt;a href="http://railstips.org/2007/7/23/autotest-growl-pass-fail-notifications"&gt;John Nunemaker&lt;/a&gt; and &lt;a href="http://blog.aisleten.com/2008/02/21/installing-growlnotify-and-autotest-for-bdd-use-with-rspec-on-leopard/"&gt;Aisle Ten&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;John&amp;#8217;s blog entry is a great high level overview of how to get it to work and Aisle Ten&amp;#8217;s post will come in very useful if you run into any problems.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry18</id>
    <published>2008-03-03T15:06:50+00:00</published>
    <updated>2008-05-18T16:16:41+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/18-dconstruct-2008" rel="alternate" />
    <title>dConstruct 2008</title>
    <content type="html">&lt;p&gt;&lt;a href="http://2008.dconstruct.org/"&gt;I absolutely love this design for dConstruct 2008&lt;/a&gt;.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry19</id>
    <published>2008-03-09T20:39:25+00:00</published>
    <updated>2008-05-18T16:16:41+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/19-intaeco-goes-live" rel="alternate" />
    <title>Intaeco goes live</title>
    <content type="html">&lt;p&gt;Due to pressing issues at work, I haven&amp;#8217;t had the chance to say that &lt;a href="http://www.intaeco.co.uk/"&gt;Intaeco&lt;/a&gt; has gone live.&lt;/p&gt;
&lt;p&gt;The company sells environmentally friendly plumbing and heating products such as solar heating systems.  The site is static in nature aside from some &lt;span class="caps"&gt;PHP&lt;/span&gt; for the contact form and jQuery is used for the javascript effects.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry20</id>
    <published>2008-03-25T21:35:22+00:00</published>
    <updated>2008-06-11T12:19:26+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/20-activemerchant-paypal-and-rails" rel="alternate" />
    <title>ActiveMerchant, Paypal and Rails</title>
    <content type="html">&lt;p&gt;&lt;span class="caps"&gt;EDIT&lt;/span&gt;: I have followed this up with a further post, &lt;a href="http://capturedsparks.com/entries/23-more-on-activemerchant-and-paypal"&gt;More on ActiveMerchant and Paypal&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve spent most of the past week playing with ActiveMerchant and Paypal in order to implement recurring billing for my app.&lt;/p&gt;
&lt;p&gt;After a false start with Datacash and some fumbling in the Paypal Sandbox, I got started with a test account for Website Payments Pro (UK).  This has the benefit of using Paypal as your gateway service and also as your merchant account.  The fees for processing are slightly higher than other gateways but I find the all in one solution worth it so far.&lt;/p&gt;
&lt;p&gt;I should mention at this point that &lt;a href="http://peepcode.com/products/activemerchant-pdf"&gt;Cody Fauser&amp;#8217;s ActiveMerchant &lt;span class="caps"&gt;PDF&lt;/span&gt;&lt;/a&gt; from PeepCode was invaluable in giving me a start to integration.  Although the book is geared towards a straightforward purchase (rather than recurring billing), the code was a great starting point.  Thankfully, the ActiveMerchant library is very well commented and easily understandable.&lt;/p&gt;
&lt;p&gt;In brief, to setup the recurring billing (implemented through Subscription model), an account is created using the subdomain as account key model. If the account is a paying account, the user is redirected to a secure page to enter their credit card details and create the subscription. The credit card information, amount to be billed and frequency are passed to Paypal in the following form:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="co"&gt;Subscription&lt;/span&gt;.recurring(amount, credit_card, options = {&lt;span class="sy"&gt;:ip&lt;/span&gt; =&amp;amp;gt; request.remote_ip})&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;This calls a method on the Subscription class which sends the data to Paypal.  If a successful response is received, the response and other information is stored in the database.&lt;/p&gt;
&lt;p&gt;In terms of updating the subscription, this is easily done with the AM library by sending the profile id (which is returned by Paypal when recurring billing is set up) along with the recurring billing request.  Using this method, credit card details, payment amount and frequency can be simply changed.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m more than happy to share the code I&amp;#8217;m using if you want to leave a comment.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry21</id>
    <published>2008-05-10T13:26:19+00:00</published>
    <updated>2008-05-18T16:16:41+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/21-busy-times" rel="alternate" />
    <title>Busy times</title>
    <content type="html">&lt;p&gt;I haven&amp;#8217;t had much opportunity to post here recently due to some travel and a mix of work on my own projects and work for clients.  Aside from my development work, I also maintain a few websites and the updates and maintenance for these have been coming thick and fast.&lt;/p&gt;
&lt;p&gt;One of my own projects is approaching fruition.  It&amp;#8217;s a small application that allows people to review coffee shops that are local to them or that they visit.  The idea came following a trip to Hull where I had about 5 hours to kill and there was no way to find details of a good coffee shop where I could spend a few hours.  I suppose I hope it may help unearth some gems and stop people heading for the nearest Starbucks or Costa.&lt;/p&gt;
&lt;p&gt;The application uses the Google Maps &lt;span class="caps"&gt;API&lt;/span&gt; and the GeoKit plugin to geocode the location of coffee houses.  I think this is the type of application that really suits having a mobile version and once the web version is sufficiently complete, I&amp;#8217;ll work on producing a mobile friendly version.  There is quite a bit to do, but I&amp;#8217;m going to push it live in the next month and hopefully get some feedback that will drive continued development.&lt;/p&gt;
&lt;p&gt;I also hope to write up a bit more detail on ActiveMerchant and PayPal as I note from the logs that the entry on that topic has received quite a bit of traffic and I think it is definitely a topic that could do with more documentation.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry22</id>
    <published>2008-05-18T18:38:23+00:00</published>
    <updated>2008-05-18T18:40:34+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/22-a-new-look" rel="alternate" />
    <title>A new look</title>
    <content type="html">&lt;p&gt;I&amp;#8217;ve spent the past few weeks working a redesign for captured sparks and this weekend, as you can see, I have put it live.&lt;/p&gt;
&lt;p&gt;I have also taken the opportunity to implement some functionality that has been missing. As you might know, captured sparks is published on my own system coded in Rails and even though I have had the basics running for a few months, there were some key things that I needed but never found the time to implement.&lt;/p&gt;
&lt;p&gt;During the course of the redesign, I&amp;#8217;ve added the following functionality:&lt;/p&gt;
&lt;h3&gt;Post Status&lt;/h3&gt;
&lt;p&gt;&lt;p /&gt;I can now classify a post as either a draft or published.&lt;/p&gt;
&lt;h3&gt;Comment Administration&lt;/h3&gt;
&lt;p&gt;&lt;p /&gt;Up until now, I have had to manage any comments by logging into the server and directly editing the database through the Rails console. I&amp;#8217;ve now added the ability to approve or reject comments in the admin area.&lt;/p&gt;
&lt;p&gt;&lt;p /&gt;I&amp;#8217;ve also made the decision to effectively ignore IE6. The site uses PNGs for titles and I&amp;#8217;ve not taken any steps to address IE6&amp;#8217;s failure in this regard. Nor have I checked to see how the site looks in IE6 generally. I&amp;#8217;m using IE conditional comments to present a friendly warning to those users with IE6 that the site may not look great and suggesting an upgrade.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry23</id>
    <published>2008-05-18T19:02:09+00:00</published>
    <updated>2008-05-18T19:13:42+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/23-more-on-activemerchant-and-paypal" rel="alternate" />
    <title>More on ActiveMerchant and Paypal</title>
    <content type="html">&lt;p&gt;I&amp;#8217;ve had a few comments asking for some more information setting up AM with Paypal. I won&amp;#8217;t profess to be an expert and there may be better ways of doing this.&lt;/p&gt;
&lt;p&gt;I am using Paypal UK Website Payments Pro and for this have set up an account that gives me access to Paypal Manager.&lt;/p&gt;
&lt;p&gt;As per my previous post, an account is created using the account key as subdomain model:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;create&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    &amp;lt;code&amp;gt;account = Account.new(params[:account])&lt;tt&gt;
&lt;/tt&gt;    @account.initial_plan = params[:plan_id]&lt;tt&gt;
&lt;/tt&gt;    if @account.save&lt;tt&gt;
&lt;/tt&gt;      @account.set_admin&lt;tt&gt;
&lt;/tt&gt;      if @account.initial_plan == &amp;quot;2&amp;quot;&lt;tt&gt;
&lt;/tt&gt;        redirect_to :host =&amp;amp;gt; account_host(&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
account.name), :controller =&amp;gt; &amp;#8216;sessions&amp;#8217;, :action =&amp;gt; &amp;#8216;new&amp;#8217;&lt;br /&gt;
      else&lt;br /&gt;
        redirect_to :host =&amp;gt; account_host(@account.name), :controller =&amp;gt; &amp;#8216;subscriptions&amp;#8217;, :action =&amp;gt; &amp;#8216;new&amp;#8217;&lt;br /&gt;
      end&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = &amp;#8220;Could not create account. Please try again.&amp;#8221;&lt;br /&gt;
      redirect_to :controller =&amp;gt; &amp;#8216;accounts&amp;#8217;, :action =&amp;gt; &amp;#8216;new&amp;#8217;&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If the customer has selected anything other than a free account, they are redirect to the new action of the subscriptions controller. I am using the subscription model to act as a join between an account and a particular plan.&lt;/p&gt;
&lt;p&gt;The template for the new action is a simple form with space for credit card information. Creating a subscription calls the following create action in the controller:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;create&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    &amp;lt;code&amp;gt;plan = Plan.find_by_id(&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
account.initial_plan)&lt;br /&gt;
    first_name = params[:cc_name].split(&amp;#8217; &amp;#8216;)&lt;sup class="footnote"&gt;&lt;a href="#fn0"&gt;0&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;
    surname = params[:cc_name].split(&amp;#8217; &amp;#8217;)&lt;sup class="footnote"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;
    name = params[:cc_name]&lt;br /&gt;
    number = params[:cc_number]&lt;br /&gt;
    amount = @plan.price*100&lt;br /&gt;
    credit_card = {&lt;br /&gt;
      :number     =&amp;gt; &amp;#8220;#{number}&amp;#8221;, &lt;br /&gt;
      :first_name =&amp;gt; &amp;#8220;#{first_name}&amp;#8221;, &lt;br /&gt;
      :last_name  =&amp;gt; &amp;#8220;#{surname}&amp;#8221;,&lt;br /&gt;
      :name       =&amp;gt; &amp;#8220;#{name}&amp;#8221;,&lt;br /&gt;
      :month      =&amp;gt; &amp;#8220;#{params[:cc_month]}&amp;#8221;, &lt;br /&gt;
      :year       =&amp;gt; &amp;#8220;#{params[:cc_year]}&amp;#8221;,        &lt;br /&gt;
      :verification_value =&amp;gt; &amp;#8220;#{params[:cc_cvv]}&amp;#8221;, &lt;br /&gt;
      :type       =&amp;gt; &amp;#8220;#{params[:cc_type]}&amp;#8221; &lt;br /&gt;
    }&lt;br /&gt;
    subscription = Subscription.recurring(amount, credit_card, options = {:ip =&amp;gt; request.remote_ip})&lt;br /&gt;
    if subscription&lt;br /&gt;
      subscription.plan_id = @plan.id&lt;br /&gt;
      subscription.account_id = @account.id&lt;br /&gt;
      subscription.save&lt;br /&gt;
      flash[:notice] = &amp;#8220;Your account has been setup.  You can now login!&amp;#8221;&lt;br /&gt;
      redirect_to matters_url&lt;br /&gt;
    else&lt;br /&gt;
      flash[:error] = &amp;#8220;&lt;span class="caps"&gt;YIKES&lt;/span&gt;!&amp;#8221;&lt;br /&gt;
      redirect_to new_subscription_url&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I have no doubt that a lot of this could be refactored into the model. At the moment, I am focussing on getting the app running, not tidying up the code. You will note the class method &amp;#8220;recurring&amp;#8221;, which is in the subscription.rb file. The code for this is taken straight from the AM pdf mentioned in my earlier post so I cannot repost that here. This method creates a connection through AM to Paypal and creates a recurring subscription. Information that is returned includes a profile id that can be used to uniquely identify a particular subscription in both the app and Paypal manager.&lt;/p&gt;
&lt;p&gt;Updating the subscription is fairly similar to creating a new subscription except you pass the profile id through so that Paypal knows which account to change.&lt;/p&gt;
&lt;p&gt;One thing to note is that it is important to ensure consistency between Paypal and the subscriptions table in your app. It is very easy to update a subscription in Paypal so that a customer is billed the correct amount but fail to update the internal record in your app. This will result in revenues being either significantly higher or lower than you expect.&lt;/p&gt;
&lt;p&gt;One of the questions in the comments to the original post is how much information in the pdf was relevant to Paypal US. I can&amp;#8217;t directly answer that but I can say that the code works as a great starting point but some re-coding will necessary to make it work for your app.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry24</id>
    <published>2008-05-27T11:53:34+00:00</published>
    <updated>2008-05-27T11:53:34+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/24-the-final-10-" rel="alternate" />
    <title>The final 10%</title>
    <content type="html">&lt;p&gt;The final 10% is always the hardest bit to do. Unfortunately, it&amp;#8217;s generally that bit that makes something really work. It stops something being OK and makes it great. It makes you go &amp;#8220;Wow&amp;#8221;.&lt;/p&gt;
&lt;p&gt;On my coffee application (I still don&amp;#8217;t have a name apart from wanna coffee?, which I don&amp;#8217;t like), the majority of the functionality is there. In its most basic form, the app works. It just doesn&amp;#8217;t have that polish and that is what I&amp;#8217;m talking about. That is the final 10% and I wouldn&amp;#8217;t be happy launching it without that polish. I&amp;#8217;m happy if some areas of functionality are not present at launch, provided they are not core to the purpose.&lt;/p&gt;
&lt;p&gt;What I don&amp;#8217;t want to do is launch at 90% of what I want, and would expect, version 1 to be like. It&amp;#8217;s that 10% that I&amp;#8217;m working on now.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry25</id>
    <published>2008-06-08T12:52:20+00:00</published>
    <updated>2008-06-08T12:53:32+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/25-want-beans" rel="alternate" />
    <title>Want Beans</title>
    <content type="html">&lt;p&gt;I&amp;#8217;m happy to announce the launch of &lt;a href="http://www.wantbeans.com/"&gt;Want Beans!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Want Beans is a social network for reviewing and rating coffee shops and finding great places to grab a coffee when you&amp;#8217;re out and about.&lt;/p&gt;
&lt;p&gt;As I mentioned in an earlier post, the idea was inspired when I had about 5 hours to kill in Hull and just wanted to find somewhere to hang out with my MacBook.&lt;/p&gt;
&lt;p&gt;I hope that you&amp;#8217;ll register and add your favourite cafe to help other people discover great places to grab a latte. To get started, please visit &lt;a href="http://www.wantbeans.com/"&gt;Want Beans&lt;/a&gt;.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry26</id>
    <published>2008-06-17T08:29:55+00:00</published>
    <updated>2008-06-17T08:42:28+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/26-receiving-emails-with-ruby-on-rails" rel="alternate" />
    <title>Receiving emails with Ruby on Rails</title>
    <content type="html">&lt;p&gt;I spent the weekend getting a little application to play nicely with emails being sent to it.  As receiving emails with Rails is something that is not written about as much as sending emails, I thought I would share my solution.&lt;/p&gt;
&lt;p&gt;This tutorial will show you how to receive emails into your application, store them in the database and forward the contents to multiple recipients.&lt;/p&gt;
&lt;p&gt;The first problem of course is getting the emails into your application.  I have root access to my server, so my solution uses Postfix.  If you don&amp;#8217;t have root access, you can use &lt;span class="caps"&gt;POP&lt;/span&gt; and there are a &lt;a href="http://wiki.rubyonrails.org/rails/pages/HowToReceiveEmailsWithActionMailer"&gt;number&lt;/a&gt; &lt;a href="http://railspikes.com/2007/6/1/rails-email-processing"&gt;of&lt;/a&gt; &lt;a href="http://www.naffis.com/blog/articles/2006/08/14/receiving-emails-and-attachments-with-rails"&gt;examples&lt;/a&gt; out there.  On with the instructions&amp;#8230;&lt;/p&gt;
&lt;p&gt;As I am hosting a number of domains on the same box, I set up my main.cf file as follows:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;virtual_alias_domains = mydomain.com&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;virtual_alias_maps = hash:&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="mod"&gt;e&lt;/span&gt;&lt;/span&gt;tc/postfix/virtual&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;I then set up my virtual file (which you may need to create) with a single line:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="iv"&gt;@mydomain&lt;/span&gt;.com rails_mailer&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;This will intercept any emails sent to mydomain.com and pass them to the rails_mailer alias, which is created in your alias file.  Mine is located in /etc/aliases: yours might be in /etc/postfix/aliases.  Add to the bottom of your aliases file:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;rails_mailer: &amp;amp;&lt;span class="c"&gt;#8220;|curl &amp;lt;del&amp;gt;F mail=&amp;amp;#8217;&amp;amp;lt;&amp;lt;/del&amp;gt;&amp;amp;#8217; http://mydomain.com/emails&amp;amp;#8221;&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;This uses curl to post the mail as form data to the given url.  The email contents will be stored inside the mail parameter.  The pipe character at the start indicates that this is a shell command and not a directory.&lt;/p&gt;
&lt;p&gt;To apply all these changes:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;sudo postmap &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;etc&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;postfix/virtual&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;sudo newaliases&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;sudo &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;etc&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="mod"&gt;ini&lt;/span&gt;&lt;/span&gt;t.d/postfix reload&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;To check that this is working, change into your /var/log directory and use:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;tail -f mail.info&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;Then send an email to any address @mydomain.com and you should see it received in your mail log and passed to your Rails app.  If you look in your app&amp;#8217;s logs, you should see it spitting out a 500 error as there is no code to handle the email&amp;#8230;yet.&lt;/p&gt;
&lt;p&gt;On to the Ruby.  Create an Emails controller and define a create method:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;create&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  if params[:mail]&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;Notifier&lt;/span&gt;.receive(params[&lt;span class="sy"&gt;:mail&lt;/span&gt;])&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;This receives the contents of params[:mail] and passes it to the receive method of our notifier model.&lt;/p&gt;
&lt;p&gt;To deal with Rails&amp;#8217; cross-site scripting protection, you need to add to the top of your controller:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;skip_before_filter &lt;span class="sy"&gt;:verify_authenticity_token&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;Next, generate a mailer called notifier.  In notifier.rb, define a method called receive(email).  Using this method name automatically invokes the power of &lt;a href="http://tmail.rubyforge.org/"&gt;TMail&lt;/a&gt;.  My receive method is as follows.  You will need to change this to make sure you pull the information you need from the email:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;15&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;receive&lt;/span&gt;(email)&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  event_name = email.to&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  event_name = event_name.to_s.sub(&amp;amp;&lt;span class="c"&gt;#8216;@mydomain.com&amp;amp;#8217;, &amp;amp;#8217;&amp;amp;#8217;)&amp;lt;br /&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  event = &lt;span class="co"&gt;Event&lt;/span&gt;.find_by_tidy_name(event_name)&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  body = email.body&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  address = &lt;span class="co"&gt;Array&lt;/span&gt;.new&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  event.attendees.each do |attendee|&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    address &amp;amp;lt;&amp;amp;lt; attendee.email.to_s&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  from = email.from.to_s&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  new_email = event.emails.new&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  new_email.from = email.friendly_from&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  new_email.body = body&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  new_email.save&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  Notifier.deliver_event_email(event, from, address, body)&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;Before running through this code, I should explain that when people use the app, they receive a dedicated email address in format myeventname@mydomain.com.&lt;/p&gt;
&lt;p&gt;This code does two things.  Firstly, it extracts the following data from the email: the name of the event, the body of the email and who the email is from.  It then constructs a new email that belongs to the event and saves to the database.  It then invokes another method in our notifier.rb to forward the email body to the individuals who are attending the event.&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;event_email&lt;/span&gt;(event, from, address, body)&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  setup_email(from)&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="iv"&gt;@bcc&lt;/span&gt; = address&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  @subject += &amp;amp;#8220;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;event.name&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;&amp;amp;#8221;&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="iv"&gt;@body&lt;/span&gt;[&lt;span class="sy"&gt;:body&lt;/span&gt;] = body&amp;lt;br &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;tt&gt;
&lt;/tt&gt;end&amp;lt;br &lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;In terms of the application that I wrote this for, I hope to launch it within the next week.  If you&amp;#8217;ve got any questions or run into any problems, leave a comment and I&amp;#8217;ll try and help.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry27</id>
    <published>2008-07-06T17:08:36+00:00</published>
    <updated>2008-07-06T17:22:14+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/27-eventamatic-" rel="alternate" />
    <title>Eventamatic!</title>
    <content type="html">&lt;p&gt;I&amp;#8217;m pleased to announce the launch of &lt;a href="http://eventamatic.com/"&gt;Eventamatic!&lt;/a&gt;, a simple way for you to manage your events.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry28</id>
    <published>2008-07-14T21:35:27+00:00</published>
    <updated>2008-07-14T21:35:27+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/28-building-buzz" rel="alternate" />
    <title>Building Buzz</title>
    <content type="html">&lt;p&gt;&lt;a href="http://www.37signals.com/"&gt;37signals&lt;/a&gt;, who are perhaps best known for Basecamp, have just posted &lt;a href="http://www.37signals.com/svn/posts/1125-the-early-days-how-37signals-built-buzz-out-of-the-gate"&gt;an interesting blog post&lt;/a&gt; on how they built buzz in their early days. It&amp;#8217;s a great look back at the origins of a company that now inspires a lot of other web design and web application companies. Not just in terms of the work they produce, but also in terms of their approach to running a business.&lt;/p&gt;
&lt;p&gt;What the post highlights is how it is not always necessary to focus on what you do provided that the things you are doing are related to your primary activity. Ideas like the E-Commerce Search Report and Design Not Found offer an &amp;#8220;in&amp;#8221; to prospective customers.&lt;/p&gt;
&lt;p&gt;I also subscribe to &lt;a href="http://sethgodin.typepad.com/"&gt;Seth Godin&lt;/a&gt; and one of the ideas he promotes is to always offer content. Seth has a new post on his blog every day (or thereabouts).&lt;/p&gt;
&lt;p&gt;It takes a concerted effort to build buzz and drive business. The posts here at captured sparks have always been a little sparse, and mainly related to web development. From now, I will be making a concerted effort to post more.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry29</id>
    <published>2008-08-07T20:12:59+00:00</published>
    <updated>2008-08-07T20:13:00+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/29-empowerment" rel="alternate" />
    <title>Empowerment</title>
    <content type="html">&lt;p&gt;I was at a meeting a couple of days ago and somebody raised a question about empowerment for the employees. They seemed to be looking for an indication from our &lt;span class="caps"&gt;CFO&lt;/span&gt; that they would be empowered to, and entitled to, make decisions without having to refer it to a manager.&lt;/p&gt;
&lt;p&gt;I found the question extremely strange as I have always considered the company for which I work to delegate a lot of responsibility to the employees. I have never felt constrained or not permitted to make a decision and thought it odd that a colleague did.&lt;/p&gt;
&lt;p&gt;One of the things I do find is that people often shirk that responsibility. They ask for it. They want it. They want to feel that the company trusts them to do the right thing. But they don&amp;#8217;t actually want to take action. They are too scared of making the wrong decision.&lt;/p&gt;
&lt;p&gt;When recruiting people, I&amp;#8217;m always interested in finding out how they respond to that kind of empowerment. I ask them for an example of when they took a wrong decision at work and how they coped with the consequences. Did it deter them from making further decisions?&lt;/p&gt;
&lt;p&gt;Giving people the power to make decisions is half the battle. Creating a culture where people feel secure in actually making them is the other half. Where they don&amp;#8217;t think they will get fired if it goes wrong. Where genuinely acting in the best interests of the company is the important thing.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry30</id>
    <published>2008-08-07T20:25:25+00:00</published>
    <updated>2008-08-07T20:25:25+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/30-want-beans-update" rel="alternate" />
    <title>Want Beans Update</title>
    <content type="html">&lt;p&gt;You no longer need to create an account to create a cafe on Want Beans. Add your favourite coffee house by visiting &lt;a href="http://wantbeans.com/cafes/new"&gt;the new cafe page&lt;/a&gt;.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry31</id>
    <published>2008-08-17T11:46:34+00:00</published>
    <updated>2008-08-17T11:47:02+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/31-equal-height-columns" rel="alternate" />
    <title>Equal height columns</title>
    <content type="html">&lt;p&gt;One of the common issues that has plagued web designers is how to ensure that a sidebar column with a background colour will fill the height of the page when a second column is much longer. One of the most used options is &lt;a href="http://www.alistapart.com/articles/fauxcolumns/"&gt; Faux Columns&lt;/a&gt; by &lt;a href="http://www.simplebits.com/"&gt;Dan Cederholm&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m going to show you how to quickly achieve identical height columns using jQuery.&lt;/p&gt;
&lt;p&gt;We start with a simple layout:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="ta"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="an"&gt;id&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="an"&gt;id&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;sidebar&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;Lorem ipsum..&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="an"&gt;id&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;Lorem ipsum&lt;span class="en"&gt;&amp;amp;#8230;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;We can then use the following jQuery code to ensure that the sidebar is always equal to the height of the content column:&lt;/p&gt;
&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&amp;lt;p&amp;gt;&lt;span class="kw"&gt;var&lt;/span&gt; mainHeight = jQuery(&amp;amp;&lt;span class="er"&gt;#&lt;/span&gt;&lt;span class="i"&gt;8216&lt;/span&gt;;&lt;span class="er"&gt;#&lt;/span&gt;main&amp;amp;&lt;span class="er"&gt;#&lt;/span&gt;&lt;span class="i"&gt;8217&lt;/span&gt;;).height();&amp;lt;br /&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="kw"&gt;if&lt;/span&gt; (mainHeight &amp;amp;gt; &lt;span class="i"&gt;280&lt;/span&gt;) {&amp;lt;br /&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    jQuery(&amp;amp;&lt;span class="er"&gt;#&lt;/span&gt;&lt;span class="i"&gt;8216&lt;/span&gt;;&lt;span class="er"&gt;#&lt;/span&gt;sidebar&amp;amp;&lt;span class="er"&gt;#&lt;/span&gt;&lt;span class="i"&gt;8217&lt;/span&gt;;).css({&amp;lt;br /&amp;gt;&lt;tt&gt;
&lt;/tt&gt;      height: mainHeight&amp;lt;br /&amp;gt;&lt;tt&gt;
&lt;/tt&gt;    });&amp;lt;br /&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  } &lt;span class="kw"&gt;else&lt;/span&gt; { &amp;lt;br /&amp;gt;&lt;tt&gt;
&lt;/tt&gt;  };&amp;lt;br /&amp;gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;This grabs the height of the #main div and if that height is greater than 280px, dynamically adjusts the height of the sidebar to match.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
  <entry>
    <id>tag:capturedsparks.com:Entry32</id>
    <published>2009-02-15T18:39:30+00:00</published>
    <updated>2009-02-15T18:39:30+00:00</updated>
    <link type="text/html" href="http://capturedsparks.com/entries/32-update-" rel="alternate" />
    <title>Update!</title>
    <content type="html">&lt;p&gt;So, my last entry here was 17th August 2008. And that was written just over a month after I said I would post more. Work took over. My full-time job was incredibly busy during the last 3 months of 2008 and the I have been working on a Rails site since October and that is still ongoing. As a result of this combination, I never really had the opportunity to post anything to the blog.&lt;/p&gt;
&lt;p&gt;For me, 2008 was a good year.  During 2007, my site received 200 visits. In 2008, it received over 1700 visits. This was driven primarily by three articles I wrote on 2 subjects &amp;#8211; combining ActiveMerchant and Paypal (something I still receive emails about) and receiving emails with Rails. The visitor numbers have kept up through January 2009 and I hope to post more this year to drive more traffic.&lt;/p&gt;
&lt;p&gt;The site I&amp;#8217;m working on at the moment is a straight-forward brochure site although I have done a nice implementation with Google Maps to show the nearest stockists for the products sold by the client.  This should be finished within the next month, following which I hope to work on a small project of my own. Nothing concrete as yet but have some ideas floating round my head.&lt;/p&gt;
&lt;p&gt;Finally, I&amp;#8217;ve been spammed massively in the comments. If you left a comment after 16 January, I&amp;#8217;m afraid I&amp;#8217;ve had to delete it as I couldn&amp;#8217;t go through 2000 comments to identify the genuine ones.  Sorry again.&lt;/p&gt;</content>
    <author>Robin Fisher</author>
  </entry>
</feed>
