<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Peer Assembly Blog</title>
    <link href="http://peerassembly.com/atom.xml" rel="self"/>
    <link href="http://peerassembly.com/"/>
    <updated>2012-01-13T15:22:35+00:00</updated>
    <id>http://peerassembly.com/</id>
    <author>
        <name>Denis Hennessy</name>
        <email>denis@peerassembly.com</email>
    </author>
    
    <entry>
        <title>Escaping Filename Spaces in Paperclip Attachment URLs</title>
        <link href="http://peerassembly.com/2011/10/14/Escaping-Filename-Spaces-in-Paperclip-Attachment-URLs"/>
        <updated>2011-10-14T00:00:00+01:00</updated>
        <id>http://peerassembly.com/2011/10/14/Escaping-Filename-Spaces-in-Paperclip-Attachment-URLs</id>
        <content type="html">&lt;p&gt;As I&amp;rsquo;ve mentioned &lt;a href=&quot;/2011/09/09/Solving-AWS-S3-NoSuchBucket-Error-When-Using-Paperclip/&quot;&gt;before&lt;/a&gt; we generally use &lt;a href=&quot;https://github.com/thoughtbot/paperclip&quot;&gt;Paperclip&lt;/a&gt; when we need to support file uploads. However, there are a couple of edge cases which Paperclip, out of the box, doesn&amp;rsquo;t solve. One of these is the correct URL escaping of uploaded filenames (at least as of version 2.3.15).&lt;/p&gt;

&lt;h2&gt;The Problem&lt;/h2&gt;

&lt;p&gt;Imagine you have a model with a Paperclip &amp;ldquo;picture&amp;rdquo; attachment&amp;hellip;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;has_attached_file&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:picture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:styles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:thumbnail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;300x200&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:storage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:s3_credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/config/s3.yml&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:default_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/images/default_picture_:style.png&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;pictures/person/:id/:style_:filename&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This would be accessed in your view using&amp;hellip;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;vi&quot;&gt;@person&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;picture&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:thumbnail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;All looks good. But Paperclip won&amp;rsquo;t URL escape the URL it generates for this attachment. The first time people generally notice this is when the uploaded filename contains spaces. If you upload a file with a name like &amp;ldquo;covent garden.png&amp;rdquo;, Paperclip will generate the invalid URL &lt;code&gt;http://s3.amazonaws.com/bucket/pictures/person/141/thumb_convent garden.png&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Drat that pesky space.&lt;/p&gt;

&lt;h2&gt;The Solution&lt;/h2&gt;

&lt;p&gt;There are two ways to solve this problem&lt;/p&gt;

&lt;h3&gt;Option 1: Rename the File on Upload&lt;/h3&gt;

&lt;p&gt;This option is generally the most popular. It involves writing a PaperClip &lt;code&gt;before_post_process&lt;/code&gt; filter which renames the file &lt;em&gt;after&lt;/em&gt; it has been uploaded. This new name can be URL safe. So even though the subsequent URLs Paperclip generates are not escaped it isn&amp;rsquo;t a problem.&lt;/p&gt;

&lt;p&gt;There are several articles on this mechanism already so I won&amp;rsquo;t go into the implementation details here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://davesouth.org/stories/make-url-friendly-filenames-in-paperclip-attachments&quot;&gt;Make URL friendly filenames in paperclip attachments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I&amp;rsquo;ve found there are several problems with this mechanism. The most obvious is that it needs to be in place before any images are uploaded.&lt;/p&gt;

&lt;h3&gt;Option 2: URL Escape the Filename When URL is Generated&lt;/h3&gt;

&lt;p&gt;My preferred option is to write a new &lt;a href=&quot;https://github.com/thoughtbot/paperclip/wiki/Interpolations&quot;&gt;Paperclip interpolation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create a new file in your ruby project..&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;config/initializers/paperclip_interpolates.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;With the following content&amp;hellip;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Paperclip by default does not escape the filenames. This interpolated&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# variables lets you access the URL escaped version of the filename.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# This should be used in the :url option of has_attached_file.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# For example...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# has_attached_file :picture, :styles =&amp;gt; { :thumbnail =&amp;gt; &amp;quot;300x200&amp;gt;&amp;quot; },&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   :path =&amp;gt; &amp;quot;pictures/person/:id/:style_:filename&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   :url =&amp;gt; &amp;#39;/pictures/person/:id/:style_:escaped_filename&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Note, this solution is not suitable for S3 based attachments.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Paperclip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interpolates&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;escaped_filename&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CGI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CGI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# To escape the S3 URL takes a little more work. In this scenerio the url&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# option should be...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# has_attached_file :picture, :styles =&amp;gt; { :thumbnail =&amp;gt; &amp;quot;300x200&amp;gt;&amp;quot; },&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   :storage =&amp;gt; :s3, :s3_credentials =&amp;gt; &amp;quot;#{Rails.root}/config/s3.yml&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   :default_url =&amp;gt; &amp;quot;/images/default_picture_:style.png&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   :url =&amp;gt; &amp;#39;:s3_escaped_path_url&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   :path =&amp;gt; &amp;quot;pictures/person/:id/:style_:filename&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Note, paperclip&amp;#39;s S3 storage component will ignore url options which don&amp;#39;t start with &amp;#39;:s3&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# and end with &amp;#39;url&amp;#39;.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Paperclip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interpolates&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;s3_escaped_path_url&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;original&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;escaped&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CGI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CGI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
  
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://s3.amazonaws.com/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bucket_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;original&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;escaped&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;%r{^/}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now update the model&amp;rsquo;s attachment to have an additional &lt;code&gt;:url&lt;/code&gt; option which uses our new &lt;code&gt;s3_escaped_path_url&lt;/code&gt; interpolation&amp;hellip;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;has_attached_file&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:picture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:styles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:thumbnail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;300x200&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:storage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:s3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:s3_credentials&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/config/s3.yml&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:default_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/images/default_picture_:style.png&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;:s3_escaped_path_url&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:path&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;pictures/person/:id/:style_:filename&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That&amp;rsquo;s all the changes you need to make. No file renaming, now all the URLs for that attachment are generated with the correct escaping.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Downloading Device UDIDs from Apple Developer Portal</title>
        <link href="http://peerassembly.com/2011/09/30/Downloading-UDID-From-Apple"/>
        <updated>2011-09-30T00:00:00+01:00</updated>
        <id>http://peerassembly.com/2011/09/30/Downloading-UDID-From-Apple</id>
        <content type="html">&lt;p&gt;Apple allows an iOS developer to associate up to 100 devices with a developer account, and use those devices for testing Ad-Hoc builds.  Although there&amp;rsquo;s an option to remove devices, &lt;em&gt;they continue to count towards the 100 device limit&lt;/em&gt;. That is, until you renew your developer account &amp;ndash; then you get a message that you can delete devices and have them no longer apply against the limit. In past years, I&amp;rsquo;ve tried to carefully prune the list, but inevitably I&amp;rsquo;ve overlooked a bunch of devices and once you start adding new devices, you can no longer delete old ones.&lt;/p&gt;

&lt;p&gt;This year, I have a new plan. I&amp;rsquo;m going to delete all devices, except for my own, and then gradually re-add client devices as they&amp;rsquo;re needed.  The developer portal has a useful option to upload a text file containing a list of devices but unfortunately doesn&amp;rsquo;t have an option to download the existing devices. Using the excellent &lt;a href=&quot;http://rubygems.org/gems/mechanize&quot;&gt;mechanize&lt;/a&gt; gem, I wrote a short script to scrape the UDIDs from the developer portal and export them to a local file.  Here&amp;rsquo;s how you use it:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;ruby dl_devices.rb myappleid mypassword &amp;gt; devices.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Here&amp;rsquo;s the source of the script:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;mechanize&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;agent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Mechanize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;https://developer.apple.com/ios/manage/devices/index.action&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Log in to Apple Developer portal if we&amp;#39;re presented with a login form&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;form_with&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;appleConnectForm&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theAccountName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theAccountPW&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;submit&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;https://developer.apple.com/ios/manage/devices/index.action&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;deviceIdentifier&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;deviceName&amp;quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Format each row as name,udid&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parser&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;//fieldset[@id=&amp;quot;fs-0&amp;quot;]/table/tbody/tr&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;at_xpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;td[@class=&amp;quot;name&amp;quot;]/span/text()&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;udid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;at_xpath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;td[@class=&amp;quot;id&amp;quot;]/text()&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;udid&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Click &lt;a href=&quot;/public/downloads/dl_devices.rb&quot;&gt;dl_devices.rb&lt;/a&gt; to download it.  It simply tries to access the device management page, fills in a login form if required, and then extracts the device name and UDID using xpath expressions.&lt;/p&gt;

&lt;h3&gt;Troubleshooting&lt;/h3&gt;

&lt;p&gt;If you get an error like &lt;code&gt;'gem_original_require': no such file to load -- mechanize (LoadError)&lt;/code&gt;, it means you don&amp;rsquo;t have the required ruby libraries installed. Install them with:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install mechanize
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;If the resulting data is missing or garbage, then it&amp;rsquo;s possible that Apple have changed the structure or flow of the developer portal. Try manually visiting &lt;a href=&quot;https://developer.apple.com/ios/manage/devices/index.action&quot;&gt;https://developer.apple.com/ios/manage/devices/index.action&lt;/a&gt; and verify that you get asked to login, and then see your list of devices. If the structure of the page has changed, you could adjust the xpath references to match. If so, please send me the changes and I&amp;rsquo;ll update this page.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Solving AWS::S3::NoSuchBucket Error When Using Paperclip</title>
        <link href="http://peerassembly.com/2011/09/09/Solving-AWS-S3-NoSuchBucket-Error-When-Using-Paperclip"/>
        <updated>2011-09-09T00:00:00+01:00</updated>
        <id>http://peerassembly.com/2011/09/09/Solving-AWS-S3-NoSuchBucket-Error-When-Using-Paperclip</id>
        <content type="html">&lt;p&gt;Very often when working on server side Ruby on Rails projects we need to support file uploads, such as pictures. To provide this support our gem of choice is &lt;a href=&quot;https://github.com/thoughtbot/paperclip&quot;&gt;Paperclip&lt;/a&gt;. We&amp;rsquo;ve used Paperclip for years and found it a huge improvement over &lt;a href=&quot;https://github.com/technoweenie/attachment_fu&quot;&gt;attachment_fu&lt;/a&gt; which we used prior to it. However, in our last project it threw us a curve ball.&lt;/p&gt;

&lt;p&gt;As we&amp;rsquo;ve done in dozens of previous projects we created an S3 bucket, configured Paperclip to use it and then started uploading files. However, uploads to the bucket failed with the following error appearing in the logs…&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;NameError &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;uninitialized constant AWS::S3::NoSuchBucket&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Petty strange since the bucket did exist.&lt;/p&gt;

&lt;p&gt;So I used my trusty &lt;a href=&quot;http://cyberduck.ch/&quot;&gt;CyberDuck&lt;/a&gt; S3 client to connect to the bucket and upload some test images. I then tried to access these with the URL Paperclip was generating for them. For example &lt;code&gt;http://s3.amazonaws.com/topsecretbucket/pictures/entity/3/pretty+picture+1.JPG?1311614390&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The Amazon server returned an illuminating response…&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Error&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;Code&amp;gt;&lt;/span&gt;PermanentRedirect&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Code&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;Message&amp;gt;&lt;/span&gt;
    The bucket you are attempting to access must be addressed using
    the specified endpoint. Please send all future requests to this endpoint.
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Message&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;RequestId&amp;gt;&lt;/span&gt;2EACG096167A1212&lt;span class=&quot;nt&quot;&gt;&amp;lt;/RequestId&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;Bucket&amp;gt;&lt;/span&gt;topsecretbucket&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Bucket&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;HostId&amp;gt;&lt;/span&gt;
    dV/835QeLLt/g/t/Lhl+SCTVTGV3uo801DBUzw+tq85Nc+gTPDTDEiq3+oTwmKcM
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/HostId&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;Endpoint&amp;gt;&lt;/span&gt;topsecretbucket.s3.amazonaws.com&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Endpoint&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Error&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Notice the endpoint Amazon recommend has the bucket name as a subdomain and not as part of the path.&lt;/p&gt;

&lt;h3&gt;Eureka!&lt;/h3&gt;

&lt;p&gt;The root of the problem was my bucket, which was configured to be located in the EU and not the US, as we&amp;rsquo;ve used in all our previous projects. Once we recreated a &amp;ldquo;US Standard&amp;rdquo; bucket the problem was solved. An examination of the Paperclip source revealed it &lt;em&gt;only&lt;/em&gt; supports US based buckets.&lt;/p&gt;

&lt;p&gt;As stated in the Amazon Simple Storage Service &lt;a href=&quot;http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?VirtualHosting.html&quot;&gt;Developer Documentation&lt;/a&gt;&amp;hellip;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Amazon S3 supports virtual-hosted-style and path-style access in all Regions. The path-style syntax, however, requires that you use the region-specific endpoint when attempting to access a bucket. For example, if you have a bucket called &lt;code&gt;mybucket&lt;/code&gt; that resides in the EU, you want to use path-style syntax, and the object is named &lt;code&gt;puppy.jpg&lt;/code&gt;, the correct URI is &lt;code&gt;http://s3-eu-west-1.amazonaws.com/mybucket/puppy.jpg&lt;/code&gt;. You will receive a “PermanentRedirect” error, an HTTP response code 301, and a message indicating what the correct URI is for your resource if you try to access a non US Standard bucket with path-style syntax using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;http://s3.amazonaws.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A different Region endpoint than where the bucket resides, for example, http://s3-euwest-1.amazonaws.com and the bucket was created with the location constraint of Northern-California&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The S3 module in Paperclip is hardcoded to use &lt;code&gt;http://s3.amazonaws.com&lt;/code&gt; and so can only reference US based buckets.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Installing PostgreSQL on Lion</title>
        <link href="http://peerassembly.com/2011/08/09/installing-postgresql-on-lion"/>
        <updated>2011-08-09T00:00:00+01:00</updated>
        <id>http://peerassembly.com/2011/08/09/installing-postgresql-on-lion</id>
        <content type="html">&lt;p&gt;OSX Lion ships with the PostgreSQL client tools, as well as a &lt;code&gt;_postgres&lt;/code&gt; daemon user. I wanted to add a full PostgreSQL server in a way that was compatible with these tools and without creating an extra user account.&lt;/p&gt;

&lt;p&gt;This recipe uses HomeBrew to do the heavy lifting. If you haven&amp;rsquo;t already got it,
head over to &lt;a href=&quot;http://mxcl.github.com/homebrew&quot;&gt;http://mxcl.github.com/homebrew&lt;/a&gt; and install it.&lt;/p&gt;

&lt;p&gt;First, make sure brew is up to date:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;brew update
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Start the install process:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;brew install postgresql
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This will take a few minutes to download and eventually end with something like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&amp;gt; Summary
/usr/local/Cellar/postgresql/9.0.4: 2577 files, 34M, built in 77 seconds
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Next, initialize the database storage with this command:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;initdb /usr/local/var/postgres
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The built-in &lt;code&gt;psql&lt;/code&gt; command (and many apps) expect to connect to a local PostgreSQL
database using a unix domain socket in &lt;code&gt;/var/pgsql_socket&lt;/code&gt;. This is currently owned by
the &lt;code&gt;_postgres&lt;/code&gt; user so we need to fix that:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo chown &lt;span class=&quot;nv&quot;&gt;$USER&lt;/span&gt; /var/pgsql_socket/
Password:
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now create a &lt;code&gt;launchctl&lt;/code&gt; configuration to start the database automatically. First, copy the default config file:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mkdir -p ~/Library/LaunchAgents
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;cp /usr/local/Cellar/postgresql/9.0.4/org.postgresql.postgres.plist ~/Library/LaunchAgents/
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now, edit &lt;code&gt;~/Library/LaunchAgents/org.postgresql.postgres.plist&lt;/code&gt; in a text editor and look for this line:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/usr/local/var/postgres/server.log&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Paste in the following lines immediately below it:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;-c&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;unix_socket_directory=/var/pgsql_socket&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;-c&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;unix_socket_group=_postgres&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;-c&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;unix_socket_permissions=0770&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Start the database server like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;launchctl load -w ~/Library/LaunchAgents/org.postgresql.postgres.plist
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Add the &lt;code&gt;_postgres&lt;/code&gt; account as a database user (with no password):&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;createuser -a -d _postgres
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Finally, verify that it&amp;rsquo;s all working by connecting:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;psql template1 -U _postgres
psql &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;9.0.4&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Type &lt;span class=&quot;s2&quot;&gt;&amp;quot;help&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;help.

&lt;span class=&quot;nv&quot;&gt;template1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You should also be able to connect with a TCP/IP connection to localhost, port 5432.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Creating Alpha Transparent Favicons on a Mac</title>
        <link href="http://peerassembly.com/2010/07/08/Creating-Alpha-Transparent-Favicons-on-a-Mac"/>
        <updated>2010-07-08T00:00:00+01:00</updated>
        <id>http://peerassembly.com/2010/07/08/Creating-Alpha-Transparent-Favicons-on-a-Mac</id>
        <content type="html">&lt;p&gt;Normally I use a very old Mac program called &lt;a href=&quot;http://homepage.mac.com/t_ogihara/software/OSX/icom-eng.html&quot;&gt;IcoMaker&lt;/a&gt; to create &lt;a href=&quot;http://en.wikipedia.org/wiki/Favicon&quot;&gt;favicons&lt;/a&gt;. The problem with IcoMaker is it can’t generate alpha transparent ico files. I recently had to design a favicon for StatusHub which was round, so the standard gif level of transparency wasn’t going to cut it. Time to roll up my sleeves and find some new, hopefully free, software…&lt;/p&gt;

&lt;p&gt;Given that favicons are based on the Windows ico format there aren’t a huge number of options available to create them on the humble Mac. Most programs claiming to support the ico format don’t support alpha transparency. For completeness, here are the set of options which don’t work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.adobe.com/products/fireworks/&quot;&gt;Fireworks CS4&lt;/a&gt; (my standard tool of choice): it doesn’t support ico files at all.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://opensword.org/Pixen/&quot;&gt;Pixen&lt;/a&gt;: can read/write ico files but can’t save them with alpha transparency.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.pixelmator.com/&quot;&gt;Pixelmator&lt;/a&gt;: can open but not save ico files.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.winterdrache.de/freeware/png2ico/&quot;&gt;png2ico&lt;/a&gt;: unix command line tool which unfortunately doesn’t compile on Mac OS X.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I also tried several online tools like &lt;a href=&quot;http://tools.dynamicdrive.com/favicon/&quot;&gt;Dynamic Drives Generator&lt;/a&gt; and the &lt;a href=&quot;http://www.favicon.cc/&quot;&gt;favicon.cc generator&lt;/a&gt; but they all had problems.&lt;/p&gt;

&lt;p&gt;Eventually &lt;a href=&quot;http://www.gimp.org/&quot;&gt;Gimp&lt;/a&gt; came to the rescue. Normally I steer clear of Gimp since I don’t like the interface but in this area it excelled. If you already have your alpha transparent png file all you need to is open it in Gimp then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select File &gt; Save As…&lt;/li&gt;
&lt;li&gt;Click on “Select File Type (By Extension)”&lt;/li&gt;
&lt;li&gt;And select “Microsoft Windows Icon” – ico, its about half way down the list&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;If you are looking for more complete instructions on building a multi-resolution favicon, from scratch in Gimp, then check &lt;a href=&quot;http://egressive.com/creating-a-multi-resolution-favicon-microsoft-windows-icon-file-including-transparency-with-the-gimp&quot;&gt;David Lane’s article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When testing your favicons in Firefox don’t forget to &lt;a href=&quot;http://www.electrictoolbox.com/clear-firefox-cache-clear-favicons/&quot;&gt;clear the cache&lt;/a&gt; to see your new designs. Note, Firefox is also the best browser to confirm your ico file’s alpha transparency is working correctly. Safari displays them on a white background while Firefox uses a faded grey background.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>HTML Editor Control of Choice</title>
        <link href="http://peerassembly.com/2010/05/26/HTML-Editor-Control-of-Choice"/>
        <updated>2010-05-26T00:00:00+01:00</updated>
        <id>http://peerassembly.com/2010/05/26/HTML-Editor-Control-of-Choice</id>
        <content type="html">&lt;p&gt;Surprisingly there are very few decent, open source HTML WYSIWYG editor controls. There are a &lt;a href=&quot;http://geniisoft.com/showcase.nsf/WebEditors&quot;&gt;whole collection&lt;/a&gt; of them but most are out of date or way too feature rich and heavy.&lt;/p&gt;

&lt;p&gt;I recently required a HTML WYSIWYG editor control for a project I was working on and so spent a couple of hours reviewing and testing the available options. Here are the few which are actually worth considering.&lt;/p&gt;

&lt;h3&gt;1) tinymce, version 3.2.4.1 (&lt;a href=&quot;http://tinymce.moxiecode.com/&quot;&gt;website&lt;/a&gt;)&lt;/h3&gt;

&lt;blockquote&gt;&lt;p&gt;&amp;ldquo;Tiny&quot;mce weights in at a hefty 176K compressed. It is one of the most popular HTML editor controls around and is quite flexible with plenty of themes and plugins. It also quite active with a new release out every 2-4 months. It was easy enough to get up and running but I found the plug-ins fairly limited and styling it was just too much work.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;2) FCKEditor, version 2.6.4 (&lt;a href=&quot;http://www.fckeditor.net/&quot;&gt;website&lt;/a&gt;)&lt;/h3&gt;

&lt;blockquote&gt;&lt;p&gt;The file size of FCKEditor depends on the browser used to render it. In my tests it came in at about 72K compressed. This is one of the granddaddy HTML editors. It has lots of features and a large web following. Unfortunately I found it just too heavy to work with. The docs weren’t great and the download, all 1.5MB of it, was so cluttered with features, plugins and skins that it was too difficult to just get something simple going. It has gathered too many features in its life to suit my needs. The team are hard at work on a total rewrite (version 3.0) which may address this.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;3) NicEdit, version 0.9 r23 (&lt;a href=&quot;http://nicedit.com/&quot;&gt;website&lt;/a&gt;)&lt;/h3&gt;

&lt;blockquote&gt;&lt;p&gt;A nice fairly light framework. Depending on which features you want to use it weights in between 25 – 32K. It uses the &lt;a href=&quot;http://www.famfamfam.com/lab/icons/silk/&quot;&gt;famfam icon set&lt;/a&gt; for its tool bar buttons (I’m a huge fan of famfam) and so has a nice clean look. As with the FCKEditor and tinymce editors, NicEdit has problems generating semantically clean XHTML. There is an experimental nicXHTML plugin which addresses this. It has known problems but so far it seems to be working fine for my needs.&lt;/p&gt;

&lt;p&gt;It has some lovely behavior built right in such as auto-expanding the text area to ensure all the content is displayed. No more grippies! Overall I thought NicEdit was well put together.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;4) wysihat, version 0.2 (&lt;a href=&quot;http://josh.github.com/wysihat/&quot;&gt;website&lt;/a&gt;)&lt;/h3&gt;

&lt;blockquote&gt;&lt;p&gt;Built on &lt;a href=&quot;http://www.prototypejs.org/&quot;&gt;Prototype&lt;/a&gt; this library weighs in at 53K (before compression). At the time of writing wysihat is at version 0.2. I had previously worked with 0.1 and the new version does fix a lot of problems. However, it still isn’t ready for prime time. On Firefox and Safari it works well but IE support lets it down. Having said this wysihat is, in my opinion, the future. It is small, lite and easy to extend. A project I’m rooting for and definitely one to keep an eye on.
And the winner is…&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;In the end I went with NicEdit. Its just so much better than the existing heavy weights and wysihat needs some more love before its ready for production. I’m sure there will be some problems with NicEdit but I feel I’m starting from a good base. I’ll keep you updated on how NicEdit holds up as development continues.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Installing Phusion Passenger on Mac OSX</title>
        <link href="http://peerassembly.com/2010/04/09/Installing-Phusion-Passenger-on-Mac-OSX"/>
        <updated>2010-04-09T00:00:00+01:00</updated>
        <id>http://peerassembly.com/2010/04/09/Installing-Phusion-Passenger-on-Mac-OSX</id>
        <content type="html">&lt;p&gt;Actually this is incredibly easy, assuming you have the gem manager installed (see here if you want instructions).&lt;/p&gt;

&lt;p&gt;The phusion installer is excellent. All you need do is open a terminal and enter&amp;hellip;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;lineno&quot;&gt;1&lt;/span&gt; sudo gem install passenger
&lt;span class=&quot;lineno&quot;&gt;2&lt;/span&gt; sudo passenger-install-apache2-module
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Then just follow the on-screen instructions with the following caveats&amp;hellip;&lt;/p&gt;

&lt;h3&gt;Caveat 1: Adding Phusion to Apache&lt;/h3&gt;

&lt;p&gt;The install suggests you add the following lines to you apache config (which can be found in /etc/apache2/httpd.conf )&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;lineno&quot;&gt;1&lt;/span&gt; LoadModule passenger_module /opt/local/lib/ruby/gems/1.8/gems/passenger-2.1.3/ext/apache2/mod_passenger.so
&lt;span class=&quot;lineno&quot;&gt;2&lt;/span&gt; PassengerRoot /opt/local/lib/ruby/gems/1.8/gems/passenger-2.1.3
&lt;span class=&quot;lineno&quot;&gt;3&lt;/span&gt; PassengerRuby /opt/local/bin/ruby
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;However, I suggest you add these to a new file in a separate conf file. Create a file with the following name and apache will load it automatically on startup.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;lineno&quot;&gt;1&lt;/span&gt; /private/etc/apache2/other/phusion.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h4&gt;Tip: Restarting Apache&lt;/h4&gt;

&lt;p&gt;The phusion install asks that you restart Apache. This can be done using:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;lineno&quot;&gt;1&lt;/span&gt; sudo apachectl -k restart
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h3&gt;Caveat 2: Deploying your Application&lt;/h3&gt;

&lt;p&gt;Again the install program is very clear. It says you should add the following to your Apache config&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;lineno&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;&amp;lt;VirtualHost&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;*:80&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;2&lt;/span&gt;   ServerName www.yourhost.com
&lt;span class=&quot;lineno&quot;&gt;3&lt;/span&gt;   DocumentRoot /somewhere/public    # Be sure to point to &amp;#39;public&amp;#39;!
&lt;span class=&quot;lineno&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;But remember to remove the comment &amp;ldquo;# Be sure to point to &amp;lsquo;public&amp;rsquo;!&amp;rdquo; or Apache will display the following error on restarted:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;DocumentRoot takes one argument, Root directory of the document tree&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Also, you should add the following after the virtualhost definition.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;lineno&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;&amp;lt;Directory&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&amp;quot;/somewhere/public&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;2&lt;/span&gt;   Options ExecCGI FollowSymLinks
&lt;span class=&quot;lineno&quot;&gt;3&lt;/span&gt;   AllowOverride all
&lt;span class=&quot;lineno&quot;&gt;4&lt;/span&gt;   Allow from all
&lt;span class=&quot;lineno&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This gives Apache access to your Rail app’s directory, getting rid of any annoying 403 ‘access denied’ errors.&lt;/p&gt;

&lt;p&gt;That’s pretty much it. Remember, by default phusion will run your application in production mode. So ensure your database.yml file has a production database configured.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Forcing IE to Redraw List Items</title>
        <link href="http://peerassembly.com/2010/01/07/Force-IE-to-Redraw-List-Items"/>
        <updated>2010-01-07T00:00:00+00:00</updated>
        <id>http://peerassembly.com/2010/01/07/Force-IE-to-Redraw-List-Items</id>
        <content type="html">&lt;p&gt;Javascript is essential in allowing developers to tailor an intuitive and accessible experience for users. Web sites are becoming a lot more dynamic and javascript is key to this progression (side note: I&amp;rsquo;m not a fan of Flash, it makes my Mac work too hard). However, as usual developers encounter lots of browser interop issues &amp;ndash; most of them with Internet Explorer.&lt;/p&gt;

&lt;p&gt;Recently I was using javascript to dynamically add extra data to an unordered list item. This worked fine in FireFox and Safari. However, it turns out Internet Explorer 6 &amp;amp; 7 are very intolerant of content being added, or removed, from list elements. The problem is they don&amp;rsquo;t recognize the list item has resized and therefore don&amp;rsquo;t redraw it.&lt;/p&gt;

&lt;p&gt;Luckily it is possible to give IE a nudge, so that it redraws the list. To do this you need to dynamically add a new child element to the list&amp;hellip; and then remove it again. Here is an example javascript function, based on Prototype, which does exactly this. This function is now part of my toolbox and I call it after I add extra content to a list item.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;lineno&quot;&gt; 1&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* IE 6 &amp;amp; 7 are very intolerant of extra content being&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;* added/removed to elements so a redraw needs to be&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;* forced.&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 4&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;*/&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;forceListRedraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Browser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;IE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7&lt;/span&gt;     &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 8&lt;/span&gt;       &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createTextNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9&lt;/span&gt; 
&lt;span class=&quot;lineno&quot;&gt;10&lt;/span&gt;       &lt;span class=&quot;nx&quot;&gt;listItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11&lt;/span&gt;       &lt;span class=&quot;nx&quot;&gt;listItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;12&lt;/span&gt; 
&lt;span class=&quot;lineno&quot;&gt;13&lt;/span&gt;       &lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;listItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ul&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;14&lt;/span&gt;       &lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;15&lt;/span&gt;       &lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;removeChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;16&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;17&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;18&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



</content>
    </entry>
    
    <entry>
        <title>Migration Helpers</title>
        <link href="http://peerassembly.com/2009/09/30/Migration-Helpers"/>
        <updated>2009-09-30T00:00:00+01:00</updated>
        <id>http://peerassembly.com/2009/09/30/Migration-Helpers</id>
        <content type="html">&lt;p&gt;Working on a migration recently I noticed the same set of operations being done repeatedly. My first reaction was to &lt;a href=&quot;http://en.wikipedia.org/wiki/Don%27t_repeat_yourself&quot;&gt;DRY&lt;/a&gt; up the code by creating a utility method, within the migration. But I was sure I’d end up needing this method in future migrations. But the question was, where should I put it?&lt;/p&gt;

&lt;p&gt;The answer was to create a migration helper!&lt;/p&gt;

&lt;p&gt;First, I created lib/migration_help.rb containing the following:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;lineno&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MigrationHelper&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;2&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;do_good_stuff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;3&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;say&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;boy, this method will be useful...&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;4&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;5&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt;6&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;undo_good_stuff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;7&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;say&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;actually on second thoughts it was stupid...&amp;quot;&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;8&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;9&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Then in my migration I added &amp;lsquo;require&amp;rsquo; and &amp;lsquo;extend&amp;rsquo; to import the MigrationHelper module.&lt;/p&gt;

&lt;p&gt;require &amp;ldquo;migration_helper&amp;rdquo;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;lineno&quot;&gt; 1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AddNewFeatureColumns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Migration&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 2&lt;/span&gt;   &lt;span class=&quot;kp&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MigrationHelper&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 3&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt; 4&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;up&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 5&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;do_good_stuff&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 6&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 7&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt; 8&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;down&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt; 9&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;undo_good_stuff&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;10&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;lineno&quot;&gt;11&lt;/span&gt;  
&lt;span class=&quot;lineno&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And that was it! The helper method names have been changed, to protect the innocent, but you get the idea. Not exactly rocket science but usefully if you need to condense your migrations.&lt;/p&gt;

&lt;p&gt;For more information I suggest you check out the excellent discussion on &lt;a href=&quot;http://guides.rubyonrails.org/migrations.html&quot;&gt;migrations, in the RailsGuides&lt;/a&gt;; after reading it I changed all my migration helper &amp;lsquo;puts&amp;rsquo; statements to &amp;lsquo;say&amp;rsquo; statements. It nice to get those little details right.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Git Stash for Quick Patches</title>
        <link href="http://peerassembly.com/2009/03/26/Git-Stash-for-Quick-Patches"/>
        <updated>2009-03-26T00:00:00+00:00</updated>
        <id>http://peerassembly.com/2009/03/26/Git-Stash-for-Quick-Patches</id>
        <content type="html">&lt;p&gt;For source control management I&amp;rsquo;m currently using &lt;a href=&quot;http://git-scm.com/&quot;&gt;git&lt;/a&gt;, actually my repository is hosted on &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; (a fantastic service and highly recommended). Git can take a little getting used to but it has several great features that &lt;a href=&quot;https://subversion.tigris.org/&quot;&gt;subversion&lt;/a&gt; just doesn’t have. My current favorite is the ability to ’stash’ work-in-progress.&lt;/p&gt;

&lt;p&gt;We’ve all been there; you’re happily working on the code, halfway through a big change, when someone asks you to quickly fix a bug. Traditionally your only option was to checkout the repository head into another directory so you could make your change there – without being forced to commit or revert the current changes you were working on. But no longer, ‘git stash’ to the rescue!&lt;/p&gt;

&lt;p&gt;Now, you can quickly park the work you are doing using&amp;hellip;&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;git stash
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This will record the current state of the working directory, saving your modifications and reverting the working directory so that it matches the head of the repository. Now you can make the small tweak to fix the bug without losing your changes. The ‘git commit’ and ‘git push’ the fix as normal. When you are happy the patch is complete type…&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;git stash apply
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now your saved modifications are restored and you can continue adding that great feature you were working on.&lt;/p&gt;

&lt;p&gt;Of course if losing your changes wasn’t a concern you could have used…&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;git reset --hard HEAD
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And all your local changes would have been lost, reverting your working copy to the latest repository head.&lt;/p&gt;

&lt;h3&gt;Useful Git Resources&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Authur Koziel has some great &lt;a href=&quot;http://arthurkoziel.com/2008/05/02/git-configuration/&quot;&gt;git configuration hints&lt;/a&gt;. I love the bash shortcuts, color coding and textmate integration.&lt;/li&gt;
&lt;li&gt;GitHub have a handy &lt;a href=&quot;http://github.com/guides/git-cheat-sheet&quot;&gt;git cheatsheet&lt;/a&gt; and if you want to dig deeper there’s alway the &lt;a href=&quot;http://www.kernel.org/pub/software/scm/git/docs/user-manual.html&quot;&gt;git user&amp;rsquo;s manual&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</content>
    </entry>
    
    <entry>
        <title>TextMate Trimming & Shortcuts</title>
        <link href="http://peerassembly.com/2009/03/17/TextMate-Trimming-%26-Shortcuts"/>
        <updated>2009-03-17T00:00:00+00:00</updated>
        <id>http://peerassembly.com/2009/03/17/TextMate-Trimming-&-Shortcuts</id>
        <content type="html">&lt;p&gt;&lt;a href=&quot;http://macromates.com/&quot;&gt;TextMate&lt;/a&gt; is my development environment of choice these days. It supports the concept of bundles as an extension mechanism. Several great bundles are shipped with TextMate and I find they cover most of my needs.&lt;/p&gt;

&lt;p&gt;Additional ones can be installed and there are several ones which aid Rails development. For a while I ran &lt;a href=&quot;http://code.leadmediapartners.com/&quot;&gt;RubyAMP&lt;/a&gt; but I found TextMate’s memory usage went through the roof. So currently I just run the vanilla set.&lt;/p&gt;

&lt;h3&gt;Hiding Unwanted Bundles&lt;/h3&gt;

&lt;p&gt;I stripped down the bundles which are available in TextMate. It ships with a wide range of bundles which just get in the way when you just want to work with HTML, CSS and Ruby/Rails.&lt;/p&gt;

&lt;p&gt;If you want to do the same go to the bundle editor, via the ‘Show Bundles’ option in the ‘Bundles’ menu and press the ‘filter’ button. For full details refer to the &lt;a href=&quot;http://manual.macromates.com/en/bundles&quot;&gt;bundles manual&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Useful Keyboard Shortcuts&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Key Modifer Legend&lt;/strong&gt; :⌘ = Command, ⌥ = Option, ^ = Ctrl, ⇧ = Shift, ⎋ = Esc, ␣ = Space, ↩ = Return/Enter, ⇥ = Tab&lt;/p&gt;

&lt;h4&gt;Global Shortcuts (work on most types of files)&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;^h = Brings up help on the current word. For example W3C reference help for HTML or Rails Doc for rb files.&lt;/li&gt;
&lt;li&gt;⌥ ⎋ = Auto complete. Suggests possible attributes, etc. For example type &amp;lt;img ⌥ ⎋ and a popup with possible attributes appears.&lt;/li&gt;
&lt;li&gt;⇥ = Expand snippet. For example in an ruby file, type : and then press tab. This expands to :label =&gt; value.&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;HTML Specific Shortcuts&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;⌘&amp;amp; = Pop-up entity/escaping commands menu.&lt;/li&gt;
&lt;li&gt;⌥⌘. = Insert close tag.&lt;/li&gt;
&lt;li&gt;⌃&amp;lt; = Make closing/opening tags for word to left of cursor.&lt;/li&gt;
&lt;li&gt;^␣ = Non breaking space.&lt;/li&gt;
&lt;/ul&gt;

</content>
    </entry>
    
</feed>
