<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>OnMyList Blog: Tag rubyonrails</title>
    <link>http://blog.onmylist.com/articles/tag/rubyonrails</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>List your pants off!</description>
    <item>
      <title>attachment_fu and s3 woes, or how I spent most of Friday</title>
      <description>&lt;p&gt;At &lt;span class="caps"&gt;OML&lt;/span&gt; we use Amazon S3 for storage, when we launched the site Gravatar was very unreliable so we had to roll our own with attachment_fu, and it worked fairly well.&lt;/p&gt;


	&lt;p&gt;With our redesign we want to make all avatars square coz the site looks better that way, so I added a JavaScript image cropper to help you crop your uploaded pictures into squares. It didn&amp;#8217;t take long to write and it worked fine in my local development machine. But I was using file_system in attachment_fu locally instead of S3. (Now in retrospect I should&amp;#8217;ve setup my own test bucket on S3)... I switched it to S3 on the beta site and it stopped working, that is, the images don&amp;#8217;t get cropped properly! After about 10 hours of tracing through attachment_fu and trying silly things such as writing my own with_image override in s3_backend.rb, in the end I only had to add a single line and a minor change. Here are the before and after code&amp;#8230;&lt;/p&gt;


	&lt;p&gt;before:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;crop2square&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;image2crop&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;find_or_initialize_thumbnail&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:full&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;image2crop&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;with_image&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;img&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="attribute"&gt;@data&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;img&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;crop&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{args[:width]}&lt;/span&gt;x&lt;span class="expr"&gt;#{args[:height]}&lt;/span&gt;+&lt;span class="expr"&gt;#{args[:x1]}&lt;/span&gt;+&lt;span class="expr"&gt;#{args[:y1]}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="ident"&gt;attachment_options&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:thumbnails&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;suffix&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;size&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;create_or_update_thumbnail&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="attribute"&gt;@data&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;suffix&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;after:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;crop2square&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;image2crop&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;find_or_initialize_thumbnail&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:full&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;image2crop&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;temp_path&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;image2crop&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;create_temp_file&lt;/span&gt;
    &lt;span class="ident"&gt;image2crop&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;with_image&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;img&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="attribute"&gt;@data&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;img&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;crop&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{args[:width]}&lt;/span&gt;x&lt;span class="expr"&gt;#{args[:height]}&lt;/span&gt;+&lt;span class="expr"&gt;#{args[:x1]}&lt;/span&gt;+&lt;span class="expr"&gt;#{args[:y1]}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="ident"&gt;attachment_options&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:thumbnails&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;suffix&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;size&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;create_or_update_thumbnail&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="attribute"&gt;@data&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;path&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;suffix&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;I don&amp;#8217;t really feel like explaining why this works right now, and if you&amp;#8217;re having the same problem I&amp;#8217;m sure you won&amp;#8217;t care either and you just want to copy and paste the code and move onto your next problem.&lt;/p&gt;


	&lt;p&gt;Hope this helps&amp;#8230;&lt;/p&gt;</description>
      <pubDate>Sat, 10 Nov 2007 04:32:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:6ac49798-431b-4601-bca0-9feb946e29d6</guid>
      <author>Andrew</author>
      <link>http://blog.onmylist.com/articles/2007/11/10/attachment_fu-and-s3-woes-or-how-i-spent-most-of-friday</link>
      <category>Ruby on Rails</category>
      <category>attachment_fu</category>
      <category>amazon</category>
      <category>s3</category>
      <category>ec2</category>
      <category>aws</category>
      <category>ruby</category>
      <category>RoR</category>
      <category>rubyonrails</category>
      <category>rails</category>
      <category>crop</category>
      <category>javascript</category>
      <trackback:ping>http://blog.onmylist.com/articles/trackback/29</trackback:ping>
    </item>
    <item>
      <title>Facebook app invites with RoR</title>
      <description>&lt;p&gt;Ray and I spent quite a while to get everything in our Facebook app to work. There were some blog posts about how get invites to work but they are outdated (and they involve some nasty FQLs).&lt;/p&gt;


	&lt;p&gt;One thing that I did was to create a beta fb application to test all this stuff out with our beta server, this helps a lot.&lt;/p&gt;


	&lt;p&gt;So in case you&amp;#8217;re going crazy adding invites to your fb app, here&amp;#8217;s how we did it. Keep in mind that the fb platform changes rapidly so by the time you read this there is probably a better way to do invites.&lt;/p&gt;


	&lt;p&gt;In your canvas partial, add a link to http://apps.facebook.com/[yourappname]/invite&lt;/p&gt;


	&lt;p&gt;here&amp;#8217;s how our invite method looks like:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;invite&lt;/span&gt;
    &lt;span class="attribute"&gt;@appname&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ENV&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;production&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;onmylist&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;onmylist_beta&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="attribute"&gt;@appid&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ENV&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;production&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="number"&gt;12345678&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="number"&gt;01234567&lt;/span&gt;

    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;fbsession&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;is_valid?&lt;/span&gt;
      &lt;span class="attribute"&gt;@friends2exclude&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;fbsession&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;friends_getAppUsers&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;uid_list&lt;/span&gt;        
    &lt;span class="keyword"&gt;end&lt;/span&gt;

    &lt;span class="ident"&gt;render&lt;/span&gt; &lt;span class="symbol"&gt;:partial&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;select_fbml&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; 
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;note: app id&amp;#8217;s are not real! :)&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s the select_fbml partial:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_xml "&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="namespace"&gt;fb&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="tag"&gt;fbml&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="namespace"&gt;fb&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="tag"&gt;subtitle&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;Invite your friends to join OnMyList&lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="namespace"&gt;fb&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="tag"&gt;subtitle&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;div&lt;/span&gt; &lt;span class="attribute"&gt;style&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;background-color:#f2fbdc;padding-bottom:0;margin-bottom:0&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&amp;gt;&lt;/span&gt;

&lt;span class="punct"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="attribute"&gt;join_button&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="attribute"&gt;CGI::escapeHTML&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&amp;lt;fb:req-choice url='http://www.facebook.com/apps/application.php?id=#{@appid}' label='Join OnMyList'&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; %&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="namespace"&gt;fb&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="tag"&gt;request-form&lt;/span&gt; 
&lt;span class="attribute"&gt;method&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;POST&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; 
&lt;span class="attribute"&gt;invite&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;true&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; 
&lt;span class="attribute"&gt;type&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;OnMyList&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; 
&lt;span class="attribute"&gt;action&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;http://apps.facebook.com/&amp;lt;%= @appname %&amp;gt;/&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="attribute"&gt;content&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Let's join OnMyList so you can list your pants off! &amp;lt;%= join_button %&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&amp;gt;&lt;/span&gt;

&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="namespace"&gt;fb&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="tag"&gt;multi-friend-selector&lt;/span&gt;
&lt;span class="attribute"&gt;rows&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="attribute"&gt;exclude_ids&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&amp;lt;%= @friends2exclude.join(',') %&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="attribute"&gt;showborder&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;false&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; 
&lt;span class="attribute"&gt;actiontext&lt;/span&gt;&lt;span class="punct"&gt;=&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Here are your friends who don't have OnMyList. Invite them now!&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="namespace"&gt;fb&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="tag"&gt;request-form&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;div&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="namespace"&gt;fb&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="tag"&gt;fbml&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;the exclude_ids param is to exclude your friends who already have the app installed.&lt;/p&gt;</description>
      <pubDate>Wed, 19 Sep 2007 16:25:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:ab6384ae-bf0b-4939-98d8-0e54aed585f4</guid>
      <author>Andrew</author>
      <link>http://blog.onmylist.com/articles/2007/09/19/facebook-app-invites-with-ror</link>
      <category>Ruby on Rails</category>
      <category>facebook</category>
      <category>application</category>
      <category>rubyonrails</category>
      <category>RoR</category>
      <trackback:ping>http://blog.onmylist.com/articles/trackback/25</trackback:ping>
    </item>
    <item>
      <title>memcached and cache_fu</title>
      <description>&lt;p&gt;After going live for about a week it became obvious that we should implement caching to help performance. I experimented with Rails&amp;#8217; page caching, but in Rails 1.2 the &lt;i&gt;expire_cache&lt;/i&gt; helper does not deal with custom routes very well. Also, our pages have view counts, ratings, etc, that change way too often for us to be able to cache the entire page.&lt;/p&gt;


	&lt;p&gt;The next thing I looked at was caching the MySQL queries, this seemed easier than implementing fragment caching, coz I found a &lt;a href="http://nubyonrails.com/articles/2006/08/17/memcached-basics-for-rails"&gt;CachedModel tutorial&lt;/a&gt; and it looked very good. Took me about an hour to get everything with CachedModel working, I then looked at the verbose output of memcached and my development.log, it didn&amp;#8217;t seem to be caching very much. After some more googling it turned out that CachedModel only caches find() queries, but we use custom finders in our models almost exclusively. To get it to cache more I had to manually cache and evict objects, which was kindda not fun.&lt;/p&gt;


	&lt;p&gt;So back to more googling, and I found a RailConf 2007 presentation  by &lt;a href="http://errtheblog.com"&gt;Chris Wanstrath&lt;/a&gt; on &lt;i&gt;cache_fu&lt;/i&gt;, it was appropriately titled &lt;a href="http://errtheblog.com/post/4872"&gt;&lt;em&gt;Kickin&amp;#8217; Ass with cache_fu&lt;/em&gt;&lt;/a&gt;. It seemed cool, and he talked about creating wrappers for custom finders, which was exactly what I needed. So I spent like an hour on it and moved from &lt;em&gt;CachedModel&lt;/em&gt; to &lt;i&gt;cache_fu&lt;/i&gt;.&lt;/p&gt;


	&lt;p&gt;I was all excited that it was so easy, almost too easy right? Yeah, I restarted my development server in &lt;a href="http://locomotive.raaum.org/"&gt;&lt;em&gt;Locomotive&lt;/em&gt;&lt;/a&gt;, loaded the main page, and was greeted with a &lt;i&gt;&amp;#8220;NoMethodError: protected method&amp;#8221;&lt;/i&gt; error. It was pretty weird, I spent quite a while trying to figure it out by going through the &lt;i&gt;cache_fu&lt;/i&gt; code, still couldn&amp;#8217;t figure out it. I emailed Chris, who was extremely helpful and replied to my mails in lightning fast speed (&lt;em&gt;thanks Chris!&lt;/em&gt;), he had never seen an error like that before either. After a while I went ahead and checked out cache_fu on our production server and ran the test suites that comes with it, it worked! Chris suspected that the problem had to do with Locomotive, I went ahead and installed a few gems to my global environment and ran the tests outside of the Locomotive sandbox, it worked! So after comparing the installed gem lists between Locomotive and MacPorts&amp;#8217; Ruby installation, I narrowed it down to the &lt;strong&gt;&lt;em&gt;Ruby-MemCache&lt;/em&gt;&lt;/strong&gt; gem. Uninstalled that, everything worked! So I thought I&amp;#8217;d blog about this in case someone run into the same problem in the future. I have no idea when I installed that gem, I guess the name looked good so I installed it.&lt;/p&gt;


	&lt;p&gt;cache_fu is pretty neat, I created finders that check if there are cached version of the data and I&amp;#8217;m using these new finders in our controllers, for example, here&amp;#8217;s how the custom finder that locates recently updated lists looks like (I&amp;#8217;ve removed some irrelevant code):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;List.recently_updated&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;category&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;find_conditions&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
  &lt;span class="ident"&gt;sort_column&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sort_direction&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;limit&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;offset&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

  &lt;span class="ident"&gt;find_conditions&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; 
    &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt; AND (lists.is_private=0 OR lists.is_private IS NULL)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="ident"&gt;lists&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;List&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;find_conditions&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;
    &lt;span class="symbol"&gt;:order&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;updated_at DESC&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="symbol"&gt;:limit&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;limit&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
    &lt;span class="symbol"&gt;:offset&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;offset&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;  

  &lt;span class="ident"&gt;lists&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;List&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;cached_perform_roster_sort&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;lists&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
    &lt;span class="ident"&gt;sort_column&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sort_direction&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

  &lt;span class="ident"&gt;lists&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The cached version of it looks like this:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;List.cached_recently_updated&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;category&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;find_conditions&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
  &lt;span class="ident"&gt;sort_column&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sort_direction&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;limit&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;offset&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

  &lt;span class="ident"&gt;get_cache&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;recently_updated:&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;category&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt;
    &lt;span class="ident"&gt;conditions&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;sort_direction&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; 
    &lt;span class="ident"&gt;limit&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;offset&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;

    &lt;span class="ident"&gt;recently_updated&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;category&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;find_conditions&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
      &lt;span class="ident"&gt;sort_column&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sort_direction&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;limit&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;offset&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;pretty clean and simple! :) We&amp;#8217;re testing the version of our site that uses memcached right now, if all goes well we will deploy it to the live site and hopefully you will enjoy a nice speedup.&lt;/p&gt;


	&lt;p&gt;Now we just have to tune the caching a bit, probably will add fragment caching to various places. Next big thing for me is to scale, right now we&amp;#8217;re considering &lt;a href="http://aws.amazon.com/ec2"&gt;&lt;span class="caps"&gt;EC2&lt;/span&gt;&lt;/a&gt; and &lt;a href="http://joyent.com/accelerator"&gt;Joyent&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Fri, 15 Jun 2007 00:12:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:af20293b-0bf3-49ef-8c6b-77306b3170d3</guid>
      <author>Andrew</author>
      <link>http://blog.onmylist.com/articles/2007/06/15/memcached-and-cache_fu</link>
      <category>Ruby on Rails</category>
      <category>cache_fu</category>
      <category>MemCached</category>
      <category>CachedModel</category>
      <category>rails</category>
      <category>rubyonrails</category>
      <category>performance</category>
      <category>cache</category>
      <category>caching</category>
      <trackback:ping>http://blog.onmylist.com/articles/trackback/15</trackback:ping>
    </item>
    <item>
      <title>aws-s3 woes</title>
      <description>&lt;p&gt;At &lt;span class="caps"&gt;OML&lt;/span&gt; we use Amazon&amp;#8217;s S3 for profile pics storage, we switched from local disk to S3 for scalability reasons when we need to move to multiple app servers or Amazon &lt;span class="caps"&gt;EC2&lt;/span&gt;. To implement S3 with &lt;a href="http://svn.techno-weenie.net/projects/plugins/attachment_fu/"&gt;attachment_fu&lt;/a&gt; was fairly straight-forward. However, we ran into a lot of problems with the aws-s3 gem. Basically the S3 backend, which uses aws-s3, failed with a broken pipe.&lt;/p&gt;


	&lt;p&gt;I did a bit of googling on this and found out the author of aws-s3 attempted to fix this in the latest subversion snapshot (# attempts changed to 10 by yours truly):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;rescue&lt;/span&gt; &lt;span class="constant"&gt;Errno&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;EPIPE&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Timeout&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Error&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Errno&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;EPIPE&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Errno&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;EINVAL&lt;/span&gt;
    &lt;span class="attribute"&gt;@http&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;create_connection&lt;/span&gt;
    &lt;span class="ident"&gt;attempts&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="number"&gt;10&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="keyword"&gt;raise&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;attempts&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt; &lt;span class="keyword"&gt;retry&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;So I checked out the latest &lt;span class="caps"&gt;SVN&lt;/span&gt; snapshot as a plugin, but it didn&amp;#8217;t quite fix it, from time to time I still got the same error. So I ended up retrying it a couple more time in my own rescue block, if it still fails, then catch the exception and fail gracefully.&lt;/p&gt;


	&lt;p&gt;It seems to work for me, feel free to post comments if you are still having problems with profile pics&amp;#8230; It would be great if you would also email the pics you tried to upload to &lt;a href="mailto:feedback@onmylist.com"&gt;feedback@onmylist.com&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;Thanks! Now go &lt;a href="http://www.onmylist.com/lists/new"&gt;list your pants off&lt;/a&gt;!&lt;/p&gt;</description>
      <pubDate>Fri, 08 Jun 2007 17:30:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:e483b46a-f4f2-44dd-b195-3ab80777d34e</guid>
      <author>Andrew</author>
      <link>http://blog.onmylist.com/articles/2007/06/08/aws-s3-woes</link>
      <category>Ruby on Rails</category>
      <category>attachment_fu</category>
      <category>amazon</category>
      <category>s3</category>
      <category>ec2</category>
      <category>aws</category>
      <category>ruby</category>
      <category>RoR</category>
      <category>rubyonrails</category>
      <category>rails</category>
      <trackback:ping>http://blog.onmylist.com/articles/trackback/10</trackback:ping>
    </item>
    <item>
      <title>Indeed we are live!</title>
      <description>&lt;p&gt;
We decided to open up &lt;a href="http://www.onmylist.com"&gt;the site&lt;/a&gt; to public last night, we only sent out a handful of email invites - only to people who wouldn't get too upset if for some unforeseen reasons we have to clear the database or lose some profile images and what not... So far so good...
&lt;/p&gt;&lt;p&gt;
Yesterday was a long day, we fixed and implemented a large number of the remaining quirks and features. Jeff re-worked the list creation and edit page, which will be re-worked yet again very soon to make them a bit more user-friendly. I decided to change profile image storage scheme from file system with &lt;a href="http://www.kanthak.net/opensource/file_column/"&gt;file_column&lt;/a&gt; to &lt;a href="http://aws.amazon.com/s3"&gt;Amazon S3&lt;/a&gt; with &lt;a href="http://clarkware.com/cgi/blosxom/2007/02/24#FileUploadFu"&gt;attachment_fu&lt;/a&gt;, there are still some quirks with profile image uploads, I am looking into that. (I think if you upload a pic that is too small it doesn't work). Moving from file_column to attachment_fu with S3 was probably a crazy thing to do on launch day but I didn't want to have to deal with migrating images from one plugin to another later on.
&lt;/p&gt;&lt;p&gt;
After we went live and cleared the test lists from the database there were a few small problems like controller actions expecting at least one list, Jeff took care of those quickly. We had a big scare when we found out &lt;a href="http://ferret.davebalmain.com/trac/wiki/FerretOnRails"&gt;Ferret&lt;/a&gt; had some &lt;strong&gt;serious&lt;/strong&gt; issues with concurrency. Basically, when more than one process try to update its index at the same time the index gets really screwed up. I moved to a &lt;a href="http://projects.jkraemer.net/acts_as_ferret/wiki/DrbServer"&gt;Rrb server&lt;/a&gt; architecture for acts_as_ferret and it fixed that problem.
&lt;/p&gt;&lt;p&gt;
We have a ton of things to work on (yes we have a good number of lists of action items!), now back to Rails hacking...
&lt;/p&gt;

</description>
      <pubDate>Tue, 05 Jun 2007 19:13:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:1cbdea85-1799-44b9-bc5a-254f6a8ed442</guid>
      <author>Andrew</author>
      <link>http://blog.onmylist.com/articles/2007/06/05/indeed-we-are-live</link>
      <category>Ruby on Rails</category>
      <category>rubyonrails</category>
      <category>rails</category>
      <category>RoR</category>
      <category>launch</category>
      <category>beta</category>
      <trackback:ping>http://blog.onmylist.com/articles/trackback/5</trackback:ping>
    </item>
  </channel>
</rss>
