<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Patrick Crosby</title>
    <link>http://blog.patrickcrosby.com/</link>
    <pubDate>Sun, 20 Apr 2008 19:33:15 GMT</pubDate>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/patrickcrosby" type="application/rss+xml" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">patrickcrosby</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://feedburner.google.com</feedburner:feedburnerHostname><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <title>Write Facebook apps using Google AppEngine</title>
      <link>http://blog.patrickcrosby.com/posts/35-Write-Facebook-apps-using-Google-AppEngine</link>
      <description>&lt;p&gt;I hacked up &lt;a href="http://code.google.com/p/minifb/"&gt;minifb&lt;/a&gt; in order to get it to work with Google AppEngine.  The result is &lt;a href="http://www.patrickcrosby.com/software/gminifb.py"&gt;gminifb&lt;/a&gt;.  It uses Google's urlfetch library instead of urllib2.&lt;/p&gt;

&lt;p&gt;To get it to work, download &lt;a href="http://www.patrickcrosby.com/software/gminifb.py"&gt;gminifb&lt;/a&gt; and place it in your application's directory.  It requires &lt;a href="http://code.google.com/p/simplejson/"&gt;simplejson&lt;/a&gt;, so put that in your app's directory as well.&lt;/p&gt;

&lt;p&gt;Here's a sample webapp.py action that uses the library:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class FacebookAction(FbHandler):
  def get(self):
    arguments = gminifb.validate(FB_SECRET_KEY, self.request)
    session_key = arguments["session_key"]
    uid = arguments["user"]

    usersInfo = gminifb.call("facebook.users.getInfo",
        FB_API_KEY, FB_SECRET_KEY, session_key=session_key,
        call_id=True, fields="name,pic_square",
        uids=uid) # uids can be comma separated list
    name = usersInfo[0]["name"]
    photo = usersInfo[0]["pic_square"]

    self.render('facebook.html', {'name': name, 'photo': photo})
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Thanks to Peter Shinners for writing the original minifb library.  My changes were very minimal...&lt;/p&gt;</description>
      <pubDate>Sun, 20 Apr 2008 19:33:15 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/35-Write-Facebook-apps-using-Google-AppEngine</guid>
    </item>
    <item>
      <title>Firefox search keyboard shortcut saves years of your life</title>
      <link>http://blog.patrickcrosby.com/posts/34-Firefox-search-keyboard-shortcut-saves-years-of-your-life</link>
      <description>&lt;p&gt;&lt;code&gt;Cmd-k&lt;/code&gt; (or &lt;code&gt;ctrl-k&lt;/code&gt;) takes you to the search box, but opens the results in the current tab.  Go to &lt;code&gt;about:config&lt;/code&gt; and change &lt;code&gt;browser.search.openintab&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; and now your search results go in a new tab.&lt;/p&gt;</description>
      <pubDate>Tue, 08 Apr 2008 03:51:23 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/34-Firefox-search-keyboard-shortcut-saves-years-of-your-life</guid>
    </item>
    <item>
      <title>Firefox 3 + del.icio.us + firebug</title>
      <link>http://blog.patrickcrosby.com/posts/33-Firefox-3-del-icio-us-firebug</link>
      <description>&lt;p&gt;Firefox 3 is now usable because there are versions of the Firebug and del.icio.us extensions that work:&lt;/p&gt;

&lt;p&gt;Firebug:  &lt;a href="http://www.getfirebug.com/releases/firebug/1.2/"&gt;http://www.getfirebug.com/releases/firebug/1.2/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;del.icio.us:  &lt;a href="http://tech.groups.yahoo.com/group/delicious-firefox-extension"&gt;http://tech.groups.yahoo.com/group/delicious-firefox-extension&lt;/a&gt; (Join the group, go to the Files section)&lt;/p&gt;</description>
      <pubDate>Mon, 07 Apr 2008 13:36:50 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/33-Firefox-3-del-icio-us-firebug</guid>
    </item>
    <item>
      <title>vim indent block of code</title>
      <link>http://blog.patrickcrosby.com/posts/32-vim-indent-block-of-code</link>
      <description>&lt;p&gt;Summary:  &lt;code&gt;Vjjjjjj=&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Enter visual line mode: &lt;code&gt;V&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Select a block of code: &lt;code&gt;jjjjjjj&lt;/code&gt; (or whatever)&lt;/p&gt;

&lt;p&gt;Indent it: &lt;code&gt;=&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Heaven...&lt;/p&gt;</description>
      <pubDate>Sat, 05 Apr 2008 16:51:00 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/32-vim-indent-block-of-code</guid>
    </item>
    <item>
      <title>rails + vim tip: :RSunittest</title>
      <link>http://blog.patrickcrosby.com/posts/31-rails-vim-tip-RSunittest</link>
      <description>&lt;p&gt;Using &lt;a href="http://rails.vim.tpope.net/"&gt;rails.vim&lt;/a&gt;, there are a bunch of ways to navigate around your project using &lt;code&gt;:R&lt;/code&gt; commands:  &lt;code&gt;:Rview&lt;/code&gt;, &lt;code&gt;:Rcontroller&lt;/code&gt;, &lt;code&gt;:Rmodel&lt;/code&gt;, &lt;code&gt;:Runittest&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;You can also do &lt;code&gt;:RS&lt;/code&gt; with any of these and they will open up in a split window.  So if you are in a model, you can do &lt;code&gt;:RSunittest&lt;/code&gt; and vim will open your unit test in a split window.&lt;/p&gt;</description>
      <pubDate>Sat, 05 Apr 2008 16:29:08 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/31-rails-vim-tip-RSunittest</guid>
    </item>
    <item>
      <title>Open a new Terminal window using Quicksilver</title>
      <link>http://blog.patrickcrosby.com/posts/30-Open-a-new-Terminal-window-using-Quicksilver</link>
      <description>&lt;p&gt;Create the following AppleScript file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tell application "Terminal"
  do script ""
end tell
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I named mine &lt;code&gt;newterm.scpt&lt;/code&gt; and put it in &lt;code&gt;~/bin&lt;/code&gt;, where I put all my little shell scripts.&lt;/p&gt;

&lt;p&gt;Once Quicksilver reindexes its catalog (you can force this), you can activate this script anywhere.  I've trained Quicksilver to use &lt;code&gt;Ctrl-space nt&lt;/code&gt;.&lt;/p&gt;</description>
      <pubDate>Wed, 26 Mar 2008 20:02:00 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/30-Open-a-new-Terminal-window-using-Quicksilver</guid>
    </item>
    <item>
      <title>Automatic production.log performance reports:  RAWK + logrotate</title>
      <link>http://blog.patrickcrosby.com/posts/29-Automatic-production-log-performance-reports-RAWK-logrotate</link>
      <description>&lt;p&gt;Killing two birds with one stone here...rotating your Rails production.log (in the default scenario, it just grows forever) and monitoring the performance of your application.&lt;/p&gt;

&lt;p&gt;First, get &lt;a href="http://rubyforge.org/frs/?group_id=2517&amp;amp;release_id=15246"&gt;rawk.rb&lt;/a&gt;.  This little script analyzes your production log and produces nice reports showing which requests are taking the most time.  Put it somewhere like &lt;code&gt;/usr/local/bin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, you want to create a logrotate config file for your app's production.log.  On a debian system, they live in &lt;code&gt;/etc/logrotate.d&lt;/code&gt;.  Here's an example in a file named &lt;code&gt;rails-example&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/var/www/example.com/shared/log/production.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    copytruncate
    prerotate
      /usr/local/bin/rawk.rb &amp;lt; /var/www/example.com/shared/log/production.log | mail -s "[example.com] rawk report" somebody@example.com
    endscript
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This tells &lt;code&gt;logrotate&lt;/code&gt; to rotate the production log every day, keep 14 days worth of copies, and before it rotates the log file, it runs &lt;code&gt;rawk&lt;/code&gt; on it and mails the result to somebody.&lt;/p&gt;</description>
      <pubDate>Tue, 18 Mar 2008 19:31:00 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/29-Automatic-production-log-performance-reports-RAWK-logrotate</guid>
    </item>
    <item>
      <title>How to make (non-stretched) square thumbnails with attachment_fu and ImageScience </title>
      <link>http://blog.patrickcrosby.com/posts/28-How-to-make-non-stretched-square-thumbnails-with-attachment-fu-and-ImageScience-</link>
      <description>&lt;p&gt;By default, if you try to make a square thumbnail from a non-square image with &lt;a href="http://svn.techno-weenie.net/projects/plugins/attachment_fu/"&gt;attachment_fu&lt;/a&gt;, it will stretch/squash the image to make it square instead of cropping it.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://seattlerb.rubyforge.org/ImageScience.html"&gt;ImageScience&lt;/a&gt; has a method called &lt;code&gt;cropped_thumbnail&lt;/code&gt; that will make a correct square thumbnail, but attachment_fu doesn't use it.&lt;/p&gt;

&lt;p&gt;To fix this, change the &lt;code&gt;resize_image&lt;/code&gt; method in &lt;code&gt;vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/image_science_processor.rb&lt;/code&gt; like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def resize_image(img, size)
  # create a dummy temp file to write to
  # ImageScience doesn't handle all gifs properly, so it converts them to
  # pngs for thumbnails.  It has something to do with trying to save gifs
  # with a larger palette than 256 colors, which is all the gif format
  # supports.
  filename.sub! /gif$/, 'png'
  content_type.sub!(/gif$/, 'png')
  self.temp_path = write_to_temp_file(filename)
  grab_dimensions = lambda do |img|
    self.width  = img.width  if respond_to?(:width)
    self.height = img.height if respond_to?(:height)
    img.save self.temp_path
    self.size = File.size(self.temp_path)
    callback_with_args :after_resize, img
  end

  size = size.first if size.is_a?(Array) &amp;amp;&amp;amp; size.length == 1
  if size.is_a?(Fixnum) || (size.is_a?(Array) &amp;amp;&amp;amp; size.first.is_a?(Fixnum))
    if size.is_a?(Fixnum)
      img.thumbnail(size, &amp;amp;grab_dimensions)
    else
      if size[0] == size[1]
        img.cropped_thumbnail(size[0], &amp;amp;grab_dimensions)
      else
        img.resize(size[0], size[1], &amp;amp;grab_dimensions)
      end
    end
  else
    new_size = [img.width, img.height] / size.to_s
    img.resize(new_size[0], new_size[1], &amp;amp;grab_dimensions)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then in your model, if you specify a thumbnail (or a resize) with square dimensions, it will use &lt;code&gt;cropped_thumbnail&lt;/code&gt; and create a proper square thumbnail:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Photo &amp;lt; ActiveRecord::Base
  has_attachment :content_type =&amp;gt; :image, 
                 :storage =&amp;gt; :file_system, 
                 :max_size =&amp;gt; 1.megabytes,
                 :resize_to =&amp;gt; '320x200&amp;gt;',
                 :thumbnails =&amp;gt; { :small =&amp;gt; [20, 20], :thumb =&amp;gt; [50, 50] },
                 :processor =&amp;gt; 'ImageScience'

  validates_as_attachment
end
&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Wed, 05 Mar 2008 02:55:46 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/28-How-to-make-non-stretched-square-thumbnails-with-attachment-fu-and-ImageScience-</guid>
    </item>
    <item>
      <title>PostgreSQL primary key sequence out of sync</title>
      <link>http://blog.patrickcrosby.com/posts/27-PostgreSQL-primary-key-sequence-out-of-sync</link>
      <description>&lt;p&gt;I'm not sure how this happened, but I kept getting &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PGError: ERROR:  duplicate key violates unique constraint...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;messages while doing a simple &lt;code&gt;INSERT&lt;/code&gt; using ActiveRecord with a PostgreSQL database, and the key was the primary key for the table.  My guess was that the primary key sequence was out of sync.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT MAX(id) FROM posts;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;returned 4, but&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT nextval('posts_id_seq');
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;returned 4 as well.&lt;/p&gt;

&lt;p&gt;I found two ways to fix it.  The first odd way is to run the &lt;code&gt;INSERT&lt;/code&gt; statement manually in &lt;code&gt;psql&lt;/code&gt;.  I don't know why it works in &lt;code&gt;psql&lt;/code&gt; and not through ActiveRecord, but I don't know why there was a problem in the first place.&lt;/p&gt;

&lt;p&gt;The second is to update the sequence manually:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT setval('posts_id_seq', (SELECT MAX(id) FROM posts)+1);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I never tried the second method as the problem hasn't returned.&lt;/p&gt;</description>
      <pubDate>Sat, 23 Feb 2008 21:01:02 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/27-PostgreSQL-primary-key-sequence-out-of-sync</guid>
    </item>
    <item>
      <title>FeedTools database cache</title>
      <link>http://blog.patrickcrosby.com/posts/26-FeedTools-database-cache</link>
      <description>&lt;p&gt;The ruby gem &lt;a href="http://sporkmonger.com/projects/feedtools/"&gt;FeedTools&lt;/a&gt; has a built-in caching mechanism.  Unfortunately, it doesn't quite work out of the box, and the documentation doesn't explain it very well.  Despite what it says, you have to tell it to explicitly use the cache in your code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/usr/bin/env ruby

require 'rubygems'
require 'feed_tools'

FeedTools.configurations[:feed_cache] = "DatabaseFeedCache"

puts "Getting feed 1st time..."
f = FeedTools::Feed.open('http://www.slashdot.org/index.rss')
puts "1. live? #{f.live?}"
puts "Getting feed 2nd time..."
f = FeedTools::Feed.open('http://www.slashdot.org/index.rss')
puts "2. live? #{f.live?}"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Assuming FeedTools can find a database.yml file and the database has the &lt;code&gt;cached_feeds&lt;/code&gt; table described in the FeedTools documentation, the above script will cache the feed after the first time and &lt;code&gt;f.live?&lt;/code&gt; will return &lt;code&gt;false&lt;/code&gt; the second time you run it.&lt;/p&gt;

&lt;p&gt;I also added an index on the &lt;code&gt;href&lt;/code&gt; column in &lt;code&gt;cached_feeds&lt;/code&gt;.  All the lookups are done on that column and the migration that comes with FeedTools doesn't have any indices.  Here's my migration for &lt;code&gt;cached_feeds&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class AddFeedToolsTables &amp;lt; ActiveRecord::Migration
  def self.up
    create_table :cached_feeds do |t|
      t.column :href, :string
      t.column :title, :string
      t.column :link, :string
      t.column :feed_data, :text
      t.column :feed_data_type, :string
      t.column :http_headers, :text
      t.column :last_retrieved, :datetime
      t.column :time_to_live, :integer
      t.column :serialized, :text
    end
    add_index :cached_feeds, :href
  end

  def self.down
    drop_table :cached_feeds
  end
end
&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Sun, 17 Feb 2008 00:51:00 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/26-FeedTools-database-cache</guid>
    </item>
    <item>
      <title>Apache 2 virtual host redirect</title>
      <link>http://blog.patrickcrosby.com/posts/25-Apache-2-virtual-host-redirect</link>
      <description>&lt;p&gt;For one of my sites, I own .org, .net, and .com for the domain and I want all the requests to go to the .org domain.  I switched to Apache 2 and this is the configuration I used:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
  ServerName india.bigpatents.com
  ServerAlias india.bigpatents.com 

  RedirectMatch (.*) http://india.bigpatents.org$1

&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Wed, 13 Feb 2008 04:32:24 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/25-Apache-2-virtual-host-redirect</guid>
    </item>
    <item>
      <title>Postgresql slow query log</title>
      <link>http://blog.patrickcrosby.com/posts/24-Postgresql-slow-query-log</link>
      <description>&lt;p&gt;Set the following variable in &lt;code&gt;postgresql.conf&lt;/code&gt; to log all queries that take longer than 100 milliseconds:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;log_min_duration_statement = 100
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;They will show up in the main &lt;code&gt;postgresql.log&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://pgfouine.projects.postgresql.org/"&gt;pgFouine&lt;/a&gt; looks like an intriguing postgresql log file analyzer, except it's written in PHP??!?&lt;/p&gt;</description>
      <pubDate>Fri, 08 Feb 2008 23:16:40 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/24-Postgresql-slow-query-log</guid>
    </item>
    <item>
      <title>Ping google blog search using ruby</title>
      <link>http://blog.patrickcrosby.com/posts/23-Ping-google-blog-search-using-ruby</link>
      <description>&lt;p&gt;With the following class, you can ping Google's &lt;a href="http://blogsearch.google.com/"&gt;blog search&lt;/a&gt; whenever you update your blog:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require 'xmlrpc/client'

class BlogPing
  def self.ping(site_name, site_url, page_url, feed_url)
    begin
      server = XMLRPC::Client.new2("http://blogsearch.google.com/ping/RPC2")
      server.call2('weblogUpdates.extendedPing', site_name, site_url, page_url, feed_url)
      return true
    rescue =&amp;gt; detail
      puts "ping failed (#{detail})"
      return false
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With any luck, it just worked on this post!&lt;/p&gt;</description>
      <pubDate>Fri, 08 Feb 2008 22:29:13 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/23-Ping-google-blog-search-using-ruby</guid>
    </item>
    <item>
      <title>Daemontools scripts for sphinx</title>
      <link>http://blog.patrickcrosby.com/posts/22-Daemontools-scripts-for-sphinx</link>
      <description>&lt;p&gt;Here are scripts to use &lt;a href="http://cr.yp.to/daemontools.html"&gt;daemontools&lt;/a&gt; to manage &lt;a href="http://www.sphinxsearch.com/"&gt;sphinx&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;run&lt;/code&gt; script (&lt;code&gt;/service/sphinx/run&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/bin/sh
echo starting
exec 2&amp;gt;&amp;amp;1
exec /usr/local/bin/searchd --console --config /var/www/example.com/current/config/sphinx/production.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;the &lt;code&gt;--console&lt;/code&gt; flag is key:  it keeps &lt;code&gt;searchd&lt;/code&gt; running in the foreground.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;log/run&lt;/code&gt; script is standard (&lt;code&gt;/service/sphinx/log/run&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/bin/sh
exec multilog t ./main
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And finally a script to reindex everything:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/bin/sh

/usr/local/bin/svstat /service/sphinx | awk -F ')| ' '{print $4}' &amp;gt; /var/www/example.com/current/tmp/pids/searchd.pid
/usr/local/bin/indexer --config /var/www/example.com/current/config/sphinx/production.conf --all --rotate
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;searchd.pid&lt;/code&gt; file is referenced in the sphinx &lt;code&gt;production.conf&lt;/code&gt; file and is used by &lt;code&gt;indexer&lt;/code&gt;.  It would be nice to just call &lt;code&gt;indexer --all&lt;/code&gt; and then &lt;code&gt;svc -h /service/sphinx&lt;/code&gt;, but &lt;code&gt;indexer&lt;/code&gt; requires the &lt;code&gt;--rotate&lt;/code&gt; flag to reindex without taking &lt;code&gt;searchd&lt;/code&gt; offline, so you have to do the &lt;code&gt;awk&lt;/code&gt; junk to get the pid first.&lt;/p&gt;</description>
      <pubDate>Fri, 08 Feb 2008 04:02:48 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/22-Daemontools-scripts-for-sphinx</guid>
    </item>
    <item>
      <title>How to fix unsupervised daemontools log scripts</title>
      <link>http://blog.patrickcrosby.com/posts/21-How-to-fix-unsupervised-daemontools-log-scripts</link>
      <description>&lt;p&gt;I am using &lt;a href="http://cr.yp.to/daemontools.html"&gt;daemontools&lt;/a&gt; and was having trouble with the log files.  The log script was not being supervised, nothing I did seemed to make it work. &lt;code&gt;svstat /service/test/log&lt;/code&gt; returned &lt;code&gt;unable to open supervise/ok: file does not exist&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The problem was that &lt;code&gt;svscan&lt;/code&gt; had picked up on my service before the log directory existed.  And no matter what I did (including restarting the service), it wasn't noticing the log directory.  I couldn't get it to notice the filesystem change because I made real directories in &lt;code&gt;/service&lt;/code&gt; for each service, not symlinks.&lt;/p&gt;

&lt;p&gt;One solution would be to reboot, but rebooting a unix box is equivalent to admitting failure.  I stopped my service, moved the service files to &lt;code&gt;/var/local/services/test&lt;/code&gt;, then symlinked the service directory into &lt;code&gt;/service&lt;/code&gt;.&lt;/p&gt;</description>
      <pubDate>Fri, 08 Feb 2008 03:30:00 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/21-How-to-fix-unsupervised-daemontools-log-scripts</guid>
    </item>
    <item>
      <title>gettext 1.10.0 and Rails 2.0</title>
      <link>http://blog.patrickcrosby.com/posts/20-gettext-1-10-0-and-Rails-2-0</link>
      <description>&lt;p&gt;The ruby gem gettext 1.10.0 doesn't work with &lt;code&gt;html.erb&lt;/code&gt; files. It's simple to fix.  In the file &lt;code&gt;.../gems/gettext-1.10.0/lib/gettext/parser/erb.rb&lt;/code&gt; change the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module GetText
  module ErbParser
    @config = {
      :extnames =&amp;gt; ['.rhtml']
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module GetText
  module ErbParser
    @config = {
      :extnames =&amp;gt; ['.rhtml', '.erb']
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With this change, the gettext system will parse all your erb files.&lt;/p&gt;</description>
      <pubDate>Thu, 07 Feb 2008 21:14:00 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/20-gettext-1-10-0-and-Rails-2-0</guid>
    </item>
    <item>
      <title>Rails fragment caching with multiple accounts </title>
      <link>http://blog.patrickcrosby.com/posts/19-Rails-fragment-caching-with-multiple-accounts-</link>
      <description>&lt;p&gt;In &lt;a href="http://railscasts.com/episodes/90"&gt;Episode 90: Fragment Caching&lt;/a&gt; railscast, there is a great, simple explanation of how to do fragment caching.&lt;/p&gt;

&lt;p&gt;I like using strings as the identifiers for the cached portion of a view, but if your site has accounts with users signed in and you want to cache fragments that change based on the user, you need to do something more.  If the user id is exposed in the url, you can use the url to generate the cache identifier.  But if the user id is hidden, then you need to do something more.&lt;/p&gt;

&lt;p&gt;First, it should be noted that if you put slashes in the cache identifier, it will treat those as directories.  So&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;% cache 'some/deep/fragment' do %&amp;gt;
Hello
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;will put the fragment in &lt;code&gt;RAILS_ROOT/tmp/cache/some/deep/fragment.cache&lt;/code&gt;.  This is good because if you have a lot of users, you won't want all their cache files in the same directory as that would slow down the filesystem dramatically.&lt;/p&gt;

&lt;p&gt;To be clear, if you did &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;% cache 'recent_contacts' do %&amp;gt;
&amp;lt;%= render :partial =&amp;gt; "/shared/contact", :collection =&amp;gt; @contacts %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;this would not work for multiple accounts as once it is cached, every account will see the same contact list.&lt;/p&gt;

&lt;p&gt;In my project, there are many accounts.  Each account has many users, but the fragments can be cached for all the users in an account, so putting the account id in the cache identifier is enough to make them unique.  &lt;/p&gt;

&lt;p&gt;So you could do&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;% cache "recent_contacts_#{@account.id}" do %&amp;gt;
&amp;lt;%= render :partial =&amp;gt; "/shared/contact", :collection =&amp;gt; @contacts %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is fine, but once you get a lot of accounts, you are going to have a lot of files in the cache directory, one for every account.  Besides slowing down the filesystem, this could even stop working if you go above the number of allowed files in a directory.&lt;/p&gt;

&lt;p&gt;My approach was to add a &lt;code&gt;cache_dir&lt;/code&gt; method to the &lt;code&gt;Account&lt;/code&gt; model that splits the accounts into many subdirectories.  There are many ways to do this that balance the directories better (hash the id, then split it up into directories to randomize where it goes), but this way is simple and makes for an easy explanation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Account &amp;lt; ActiveRecord::Base

  # ...

  def cache_dir
    unless @cache_dir
      x = sprintf("%08d", self.id)
      @cache_dir = x[0..1] + "/" + x[2..3] + "/" + x[4..5] + "/" + x[6..7]
    end
    @cache_dir
  end

end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then the cache statements in the views look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;% cache "#{@account.cache_dir}/contacts/recent" do %&amp;gt;
&amp;lt;%= render :partial =&amp;gt; "/shared/contact", :collection =&amp;gt; @contacts %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So the recent contacts for account id 1 would go into &lt;code&gt;tmp/cache/00/00/00/01/contacts/recent&lt;/code&gt;.  It keeps it fairly clean and keeps all the cache files separated by account ids.  Once I hit 10,000,000 accounts, I'll need to adjust this, but that's a good problem to have.&lt;/p&gt;</description>
      <pubDate>Wed, 30 Jan 2008 23:38:19 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/19-Rails-fragment-caching-with-multiple-accounts-</guid>
    </item>
    <item>
      <title>Rails 2: Custom source annotations</title>
      <link>http://blog.patrickcrosby.com/posts/18-Rails-2-Custom-source-annotations</link>
      <description>&lt;p&gt;Rails 2.0 has the new &lt;code&gt;rake notes:...&lt;/code&gt; tasks built in.  If you annotate your code with &lt;code&gt;OPTIMIZE&lt;/code&gt;, &lt;code&gt;FIXME&lt;/code&gt;, or &lt;code&gt;TODO&lt;/code&gt; comments, then &lt;code&gt;rake notes&lt;/code&gt; will show all of them, &lt;code&gt;rake notes:fixme&lt;/code&gt; will show just the &lt;code&gt;FIXME&lt;/code&gt; comments.&lt;/p&gt;

&lt;p&gt;What if you want annotations of other comments?  I've been using &lt;code&gt;XXX&lt;/code&gt; for a few years now, so I wrote the following in &lt;code&gt;lib/tasks/notes.rake&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require 'source_annotation_extractor'

namespace :notes do
  desc "Enumerate all XXX annotations"
  task :xxx do
    SourceAnnotationExtractor.enumerate "XXX"
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now I can run &lt;code&gt;rake notes:xxx&lt;/code&gt; and see all my &lt;code&gt;XXX&lt;/code&gt; comments in the project.  They don't show up in the global &lt;code&gt;rake notes&lt;/code&gt; task, but...&lt;/p&gt;</description>
      <pubDate>Wed, 30 Jan 2008 10:24:00 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/18-Rails-2-Custom-source-annotations</guid>
    </item>
    <item>
      <title>git: fatal: empty ident &lt;git@example.com&gt; not allowed</title>
      <link>http://blog.patrickcrosby.com/posts/17-git-fatal-empty-ident-git-example-com-not-allowed</link>
      <description>&lt;p&gt;I use git like I used to use svn:  one central repository, clients push/pull to it.  I recently migrated the repository from a crappy Virtuozzo VPS (horrible, horrible disk access times...had to wait many seconds for &lt;code&gt;ls&lt;/code&gt; to run) to a Xen one.&lt;/p&gt;

&lt;p&gt;Everything seemed fine until today when I did my first &lt;code&gt;git push&lt;/code&gt;, which returned the error:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;fatal: empty ident &amp;amp;lt;git@example.com&amp;amp;gt; not allowed
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It took me a while to figure out as &lt;code&gt;.git/config&lt;/code&gt; had my user information set, and I even had a &lt;code&gt;~/.gitconfig&lt;/code&gt; file with default user information set.  The &lt;a href="http://git.or.cz/gitwiki/GitFaq"&gt;git faq&lt;/a&gt; has an entry for this problem, but doesn't mention server set-up.&lt;/p&gt;

&lt;p&gt;The problem was the &lt;code&gt;git&lt;/code&gt; user on my new server didn't have any name information in &lt;code&gt;/etc/passwd&lt;/code&gt;.  It didn't have this on the old server either, but for whatever reason it needed it on the new one (the old server is too slow to bother investigating).  I changed &lt;code&gt;/etc/passwd&lt;/code&gt; on the server, giving the &lt;code&gt;git&lt;/code&gt; user the full name of 'Git Git' and everything worked fine.  It's weird that it cares...in the log, this user never shows up.  Must be something to do with merging?  Anyway, it works...&lt;/p&gt;</description>
      <pubDate>Wed, 30 Jan 2008 10:01:00 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/17-git-fatal-empty-ident-git-example-com-not-allowed</guid>
    </item>
    <item>
      <title>How to get acts_as_audited to work with Rails 2</title>
      <link>http://blog.patrickcrosby.com/posts/10-How-to-get-acts-as-audited-to-work-with-Rails-2</link>
      <description>&lt;p&gt;The &lt;code&gt;audit.rb&lt;/code&gt; file in the great &lt;a href="http://opensoul.org/2006/7/21/acts_as_audited"&gt;acts_as_audited&lt;/a&gt; plugin requires &lt;code&gt;acts_as_list&lt;/code&gt;, which in Rails 2 is now a plugin.  So install the &lt;code&gt;acts_as_list&lt;/code&gt; plugin, then add the following to &lt;code&gt;environment.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;config.plugins = [:acts_as_list, :all]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will force rails to load &lt;code&gt;acts_as_list&lt;/code&gt; before &lt;code&gt;acts_as_audited&lt;/code&gt; and everything will work well...&lt;/p&gt;</description>
      <pubDate>Tue, 11 Dec 2007 16:50:00 GMT</pubDate>
      <guid>http://blog.patrickcrosby.com/posts/10-How-to-get-acts-as-audited-to-work-with-Rails-2</guid>
    </item>
  </channel>
</rss>
