<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.rowtheboat.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en" xml:base="http://www.rowtheboat.com/wp-atom.php">
	<title type="text">rowtheboat</title>
	<subtitle type="text">The online home of George Palmer</subtitle>

	<updated>2010-01-12T14:16:29Z</updated>
	<generator uri="http://wordpress.org/" version="2.8.6">WordPress</generator>

	<link rel="alternate" type="text/html" href="http://www.rowtheboat.com" />
	<id>http://www.rowtheboat.com/feed/atom</id>
	

			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.rowtheboat.com/Rowtheboat" /><feedburner:info uri="rowtheboat" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
		<author>
			<name>george</name>
						<uri>http://</uri>
					</author>
		<title type="html"><![CDATA[AB Testing with Google Analytics]]></title>
		<link rel="alternate" type="text/html" href="http://feeds.rowtheboat.com/~r/Rowtheboat/~3/TyC4hO2UKfI/39" />
		<id>http://www.rowtheboat.com/?p=39</id>
		<updated>2010-01-12T14:16:29Z</updated>
		<published>2010-01-12T14:16:29Z</published>
		<category scheme="http://www.rowtheboat.com" term="Uncategorized" /><category scheme="http://www.rowtheboat.com" term="ab testing" /><category scheme="http://www.rowtheboat.com" term="google analytics" />		<summary type="html"><![CDATA[I love AB testing. I think it is either related to the fact I did a year of Maths at university before switching to Computer Science or because human psychology fascinates me.  Either way when I launched 5ft Shelf I was keen to test lots.  First on the agenda was the default shelf [...]]]></summary>
		<content type="html" xml:base="http://www.rowtheboat.com/archives/39"><![CDATA[<p>I love AB testing. I think it is either related to the fact I did a year of Maths at university before switching to Computer Science or because human psychology fascinates me.  Either way when I launched <a href="http://www.5ftshelf.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.5ftshelf.com');">5ft Shelf</a> I was keen to test lots.  First on the agenda was the default shelf view.   For those not familiar with the site you can view a shelf of books in one of two ways &#8211; cover view or spine view as we call it on the site (see screenshots &#8211; click to enlarge).  Whilst my designer was sure that the cover view would be better I knew the target audience wasn&#8217;t necessarily technical, and besides the cool factor of a 3D book shelf would capture attention.  It was going to be an interesting AB test.</p>
<p><a href="http://www.rowtheboat.com/wp-content/uploads/2010/01/Screen-shot-2010-01-12-at-13.21.20.png" ><img src="http://www.rowtheboat.com/wp-content/uploads/2010/01/Screen-shot-2010-01-12-at-13.21.20-preview.png" alt="Cover view preview" width="580" height="128" class="aligncenter size-full wp-image-50" /></a></p>
<p><a href="http://www.rowtheboat.com/wp-content/uploads/2010/01/Screen-shot-2010-01-12-at-13.21.07.png" ><img src="http://www.rowtheboat.com/wp-content/uploads/2010/01/Screen-shot-2010-01-12-at-13.21.07-preview.png" alt="The spine view" width="580" height="136" class="aligncenter size-full wp-image-46" /></a></p>
<p>Traditionally when doing AB testing I&#8217;ve added the logic to the rails model (it doesn&#8217;t really matter if you&#8217;re not a rails developer, the point is it was in the application database).  This had a few disadvantages.  First up it didn&#8217;t keep code or the database as clean as it could be in places.  Secondly tools had to be built to then analyse the data and thirdly it couldn&#8217;t be easily plotted against relevant variables such as those stored in analytics software.</p>
<p>So when Google <a href="http://analytics.blogspot.com/2009/12/new-google-analytics-api-features.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/analytics.blogspot.com');">announced custom variable support in Analytics</a> I sat up and paid attention.  By passing through my AB test number to Google Analytics I can do all the reporting associated with AB testing outside my application database and report against more complex metrics that I don&#8217;t store such as bounce rate.  Perfect, so let&#8217;s get started:</p>
<p>The first step is to assign each user to your site a unique AB test number.  I went for a random number in the range 1 to 120.  Why so large?  Well most AB test I perform are just 2 or 3 options.  Depending on traffic you can go much larger but to be honest it becomes harder to understood the factors that lead to the users choice if you do that.  Anyway 120 is 2*3*4*5 which means you can have 2, 3, 4 or 5 options (or any product of these numbers &#8211; eg 6,8&#8230;).  This gives plenty of options for the future.  So for every visitor that comes to 5ft Shelf they get a random number and this remains with them (unless they clear out their cookies).</p>
<p>I then pass this number through to Google Analytics via a custom variable.  For example:</p>
<pre class="brush: jscript;">
var gaJsHost = ((&quot;https:&quot; == document.location.protocol) ? &quot;https://ssl.&quot; : &quot;http://www.&quot;);
    document.write(unescape(&quot;%3Cscript src='&quot; + gaJsHost + &quot;google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E&quot;));

    try {
    var pageTracker = _gat._getTracker(&quot;UA-11028671-1&quot;);
    pageTracker._setCustomVar(1, &quot;shelf_view&quot;, &quot;USERS_AB_NUMER&quot;, 1);
    pageTracker._trackPageview();
    } catch(err) {}
</pre>
<p>The USERS_AB_NUMBER needs replacing with the users actual ab number.  In ruby I used:</p>
<pre class="brush: ruby;">
@site_preferences.ab_test_number.modulo(2)
</pre>
<p>as I was only testing two options.  You can substitute this code as appropriate for the number of AB choices you have (and to your language of choice if not using Ruby).</p>
<p>A few notable things:</p>
<ul>
<li>The first argument in the custom variable index number.  Google analytics provides you with 5 of these so you can feasibly track upto five AB tests at once.</li>
<li>The second argument is the name.  I use this to identify the name of the AB test for easy identification in Analytics at a later date</li>
<li>The third argument is the value we want to store against the name.  I used the ab number modulo 2 as that is what is used to display the different options in the view of the application.  If you use more complex logic you should substitute it here.  You&#8217;re not limited to numbers though &#8211; you can also store strings</li>
<li>The last argument is the the scope of the variable.  For AB testing you&#8217;ll nearly always want 1 for visitor level.  More on this can be found in the <a href="http://code.google.com/apis/analytics/docs/tracking/gaTrackingCustomVariables.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/code.google.com');">Analytics help centre</a> if you need it</li>
</ul>
<p>Note: you can just pass through the AB test number but you will have to combine each number&#8217;s entries into 2 sets in this example.  This is a real pain as one set will be 1,3,5,..119 the next 2,4,6,..120, so unless you like maths best let your application do the logic and keep the data in analytics simple.</p>
<p>Now we&#8217;ve passed the data through to Google Analytics we need to make application specific logic in your views to render the different AB tests (again substitute for your test setup and language):</p>
<pre class="brush: ruby;">
  if @site_preferences.ab_test_number.modulo(2) == 0
    # Render option 1
  else
    # Render option 2
  end
</pre>
<p><a href="http://www.rowtheboat.com/wp-content/uploads/2010/01/Screen-shot-2010-01-12-at-14.00.43.png" ><img src="http://www.rowtheboat.com/wp-content/uploads/2010/01/Screen-shot-2010-01-12-at-14.00.43-300x155.png" alt="Custom report in Google Analytics" width="300" height="155" class="alignleft size-medium wp-image-60" align="left" /></a>Finally we need to create a custom report in Google Analytics.  Login and click &#8216;Custom Reporting&#8217; down the left hand side.  Then click &#8216;Manage Custom Reports&#8217; underneath and then &#8216;Create new report&#8217;.  You can then drag the metrics which you wish to measure along the top (think what would constitute as a success in your test &#8211; longer page views, lower bounce rate etc) and the dimensions down below (you&#8217;ll probably only want the Custom Variables here).  Make sure you get the Custom Variable values not the keys.  The screenshot on the left should show you how it looks (click to increase size).</p>
<p><a href="http://www.rowtheboat.com/wp-content/uploads/2010/01/Screen-shot-2010-01-12-at-14.00.14.png" ><img src="http://www.rowtheboat.com/wp-content/uploads/2010/01/Screen-shot-2010-01-12-at-14.00.14-300x208.png" alt="Bounce Rate by Shelf View" width="300" height="208" class="alignright size-medium wp-image-61" align="right" /></a>Then it&#8217;s just a case of waiting however long you want to run your test case for  and logging into analytics to see the results.  You&#8217;ll hopefully end up with a chart looking something like the one shown on the right (click to increase size).  Note here the real data you&#8217;re after is not in the graph but the table below.</p>
<p>So for those of you that asked that&#8217;s why 5ft Shelf switched to spine view as the default, there&#8217;s your answer :D  Happy AB testing folks.</p>
]]></content>
		<link rel="replies" type="text/html" href="http://www.rowtheboat.com/archives/39#comments" thr:count="12" />
		<link rel="replies" type="application/atom+xml" href="http://www.rowtheboat.com/archives/39/feed/atom" thr:count="12" />
		<thr:total>12</thr:total>
	<feedburner:origLink>http://www.rowtheboat.com/archives/39</feedburner:origLink></entry>
		<entry>
		<author>
			<name>george</name>
						<uri>http://</uri>
					</author>
		<title type="html"><![CDATA[5ft Shelf]]></title>
		<link rel="alternate" type="text/html" href="http://feeds.rowtheboat.com/~r/Rowtheboat/~3/CTy6XHOQlU4/38" />
		<id>http://www.rowtheboat.com/?p=38</id>
		<updated>2009-10-28T09:47:55Z</updated>
		<published>2009-10-28T09:47:02Z</published>
		<category scheme="http://www.rowtheboat.com" term="Uncategorized" /><category scheme="http://www.rowtheboat.com" term="5ftshelf" /><category scheme="http://www.rowtheboat.com" term="gettingreal" /><category scheme="http://www.rowtheboat.com" term="productivity" />		<summary type="html"><![CDATA[For the last six months I&#8217;ve been alternating between freelancing and working on my own personal projects.  It&#8217;s one of the main reasons I went freelance, so it was great to finally make the time to do it.  In particular though, there was a itch I really wanted to scratch.  I first learnt of the [...]]]></summary>
		<content type="html" xml:base="http://www.rowtheboat.com/archives/38"><![CDATA[<p><a href="http://www.5ftshelf.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.5ftshelf.com');"><img src="http://www.rowtheboat.com/wp-content/uploads/2009/10/5ftshelf-logo.png" align="left" style="10px;"></a>For the last six months I&#8217;ve been alternating between freelancing and working on my own personal projects.  It&#8217;s one of the main reasons I went freelance, so it was great to finally make the time to do it.  In particular though, there was a itch I really wanted to scratch.  I first learnt of the <a href="http://en.wikipedia.org/wiki/Harvard_Classics" onclick="javascript:pageTracker._trackPageview('/outbound/article/en.wikipedia.org');">Harvard Classics</a> a few years ago and since then the idea has really struck a chord with me &#8211; a sort of popular list of books that one should read to have a liberal education.  As I read more about the collection of books I became  more interested in what the modern equivalent would be &#8211; what are the quintessential books one should read 100 years later?</p>
<p>Today I can announce  <a href="http://www.5ftshelf.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.5ftshelf.com');">5ft Shelf</a> &#8211; a site to do just that:</p>
<blockquote><p>In 1909 Dr Eliot, then President of Harvard University, claimed a liberal education could be achieved by reading a collection of books that would total no more than 5ft in width. A local publisher challenged him to name them and he responded with what became known as the Harvard Classics.</p>
<p>Shifting forward 100 years and into the age of the internet, we&#8217;re trying to find out what the modern equivalent would be.  A lot has happened in the last century and we felt it would be impossible to get a fair representation of people’s interests without introducing two quintessential formats for modern living—music albums and movies.</p>
<p>Rather than use a single authoritative source for the modern shelf, we&#8217;ve taken the opposite approach by allowing users to create their own shelf.  We then combine all the users&#8217; shelves to find the most popular items and create our top 5ft shelf (&#8221;the ultimate shelf&#8221;).</p></blockquote>
<p>The sites offers a little more than the introduction eludes to.  Amongst other features, mini-shelves contain the most popular items in a given subject area and the recommendation algorithm makes personalised recommendations based on the items on your shelf.  For more details read the <a href="http://blog.5ftshelf.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/blog.5ftshelf.com');">5ft Shelf blog</a> <a href="http://blog.5ftshelf.com/2009/10/28/going-live/" onclick="javascript:pageTracker._trackPageview('/outbound/article/blog.5ftshelf.com');">Going Live post</a></p>
<p>As with all projects there has been big highs and hard lows but overall it has been great fun and scratching a personal itch was particularly satisfying.  On a more technical / agile development note I intend to publish two separate blog posts on the results of my endeavors.  The first will be on <a href="http://www.5ftshelf.com/books/B001CJUHSI/Getting-Real-The-smarter-faster-easier-way-to-build-a-successful-web-Application" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.5ftshelf.com');">Getting Real</a> and my experiences using the 37 signals development approach, along with some productivity experiments I performed myself during the time.  The second will be on how long it takes to get a startup to market.  I&#8217;m used to tracking time spent on projects for clients so I did the same for this project and found some interesting results.</p>
<p>Look for both blog posts in the coming weeks and in the meantime please do check out <a href="http://www.5ftshelf.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.5ftshelf.com');">5ft Shelf</a> and pass it along to anyone who you think might be interested.</p>
]]></content>
		<link rel="replies" type="text/html" href="http://www.rowtheboat.com/archives/38#comments" thr:count="5" />
		<link rel="replies" type="application/atom+xml" href="http://www.rowtheboat.com/archives/38/feed/atom" thr:count="5" />
		<thr:total>5</thr:total>
	<feedburner:origLink>http://www.rowtheboat.com/archives/38</feedburner:origLink></entry>
		<entry>
		<author>
			<name>george</name>
						<uri>http://</uri>
					</author>
		<title type="html"><![CDATA[CouchDB and ORMs]]></title>
		<link rel="alternate" type="text/html" href="http://feeds.rowtheboat.com/~r/Rowtheboat/~3/JOkTDDaGExQ/37" />
		<id>http://www.rowtheboat.com/?p=37</id>
		<updated>2009-03-29T14:39:25Z</updated>
		<published>2009-03-29T14:39:25Z</published>
		<category scheme="http://www.rowtheboat.com" term="Uncategorized" /><category scheme="http://www.rowtheboat.com" term="couchdb" /><category scheme="http://www.rowtheboat.com" term="couch_foo" /><category scheme="http://www.rowtheboat.com" term="rails" />		<summary type="html"><![CDATA[Alex did a good introduction talk to CouchDB at Scotland on Rails.  Towards the end of the talk he did an overview of the current ruby plugins/gems available for interfacing with CouchDB, one of which was my own CouchFoo.  Alex&#8217;s opinion was that any ORM for CouchDB should be as thin as possible [...]]]></summary>
		<content type="html" xml:base="http://www.rowtheboat.com/archives/37"><![CDATA[<p><a href="http://twitter.com/langalex" onclick="javascript:pageTracker._trackPageview('/outbound/article/twitter.com');">Alex</a> did a good introduction talk to CouchDB at <a href="http://scotlandonrails.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/scotlandonrails.com');">Scotland on Rails</a>.  Towards the end of the talk he did an overview of the current ruby plugins/gems available for interfacing with CouchDB, one of which was my own <a href="http://github.com/georgepalmer/couch_foo/tree/master" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">CouchFoo</a>.  Alex&#8217;s opinion was that any ORM for CouchDB should be as thin as possible just wrapping the Ruby to JSON object translation.  I raised my opinion in the question section at the end by saying that I didn&#8217;t agree and thought the ORM should map the level of functionality available in ActiveRecord.  This sparked a debate both in the talk and via Twitter of the best approach for an ORM for CouchDB to take.  As a result I agreed to write this blog post to outline my views.</p>
<p>CouchDB is a document orientated database with a HTTP interface amongst other features.  When I first started using it I played with the database a lot via simple interactions through CURL.  In the same way I feel it is important to know SQL before using any higher level API to store and retrieve objects in a relational database, I feel it is important to understand how CouchDB works before using a library to interact with it.  As with most areas of computing you will find a range of opinions over what level you interact with the database &#8211; there are the purists who like to write SQL queries for each database query performed and those who are willing to sacrifice a bit of performance (maybe not having the optimum query run each time) for the time efficiencies realized whilst developing.  I align quite well with the Rails mantra on this one &#8211; I&#8217;m willing to sacrifice perfect SQL each time for the efficiency gains made whilst developing.  Part of Alex&#8217;s argument was that you should be as close to the database as possible because the Ruby to JSON conversion is much less than the Ruby to SQL conversion.  Whilst I don&#8217;t disagree that it&#8217;s important to know how CouchDB works, I do disagree on the level at which any Ruby library should sit.  I&#8217;m happy to pay a small price in terms of extra ruby code executed because I want as clean as DSL as possible.</p>
<p>Whilst developing CouchDB I tried all the existing ruby libraries and as I worked through them I ran into several issues.  After using ActiveRecord&#8217;s save and find methods it was particularly annoying to use a library that used different method names for the same conceptual operations (eg get instead of find).  This wasn&#8217;t a major issue of course I just forked the library and made changes.  But as time went on there were features that I missed from ActiveRecord.  Validations, callbacks, finders and associations were the prime contenders.  Then dynamic finders and named scopes got added to the list.  In the end changing the existing libraries became so much work I decided to start with ActiveRecord and work from there.</p>
<p>Of the features in ActiveRecord Associations are perhaps the most controversial on whether they should apply to Document orientated databases or not.  The argument goes that if you&#8217;re trying to use associations you don&#8217;t understand how CouchDB should be used.  I disagree on this point &#8211; a simple counter argument is presented by having a document that allows comments.  Those comments could be stored inline in the document itself or in separate documents that have a reference to their parent.  This is association whichever way you look at it.  Which approach you decide to use will depend on your application and the characteristics of it.  Incidentally Alex&#8217;s gem did a great job of this letting the user specify in the association whether they wanted the object stored inline or not.  This has since been removed from his gem but is something that&#8217;s definitely on the TODO list for CouchFoo.</p>
<p>For me CouchDB lends itself well to two distinct domains.  Firstly domains where documents are used &#8211; that is an object where the fields that are stored to the database change depending on the object.  Secondly domains where you wish to take advantage of some of CouchDB&#8217;s features not present (or poorly implemented) in relational databases &#8211; a HTTP interface, fantastic scaling ability due to bi-directional replication, and schema free nature (<a href="http://bret.appspot.com/entry/how-friendfeed-uses-mysql" onclick="javascript:pageTracker._trackPageview('/outbound/article/bret.appspot.com');">see this excellent article on friendfeed experience with MySQL</a>) are just a few that spring to mind.  People may use CouchDB for the second set of criteria even though their database design could be considered quite structured, and I fully expect this group of people to rise as CouchDB reaches 1.0.  However that wasn&#8217;t why I wrote CouchFoo, my project fell into the first domain.  Whilst I provided a way to use ActiveRecord&#8217;s higher level API I also provided access to a database object that allows simple storage and retrieval of documents by id.  If that is all the functionality you require then I would expect CouchREST would be a better choice.  However I believe in reality you will quickly find you need to add validations to a field, or maybe add an association or two.  And as soon as you start on that slope I believe CouchFoo to be a better choice.</p>
<p>Ultimately I created CouchFoo as I missed the richness of the ActiveRecord API.  Whilst I don&#8217;t believe my library will be perfect for everyone it has received a lot of good feedback.  To paraphrase DHH I didn&#8217;t create the perfect framework for everyone else, I created it for me.  I only hope that other people find it useful.</p>
]]></content>
		<link rel="replies" type="text/html" href="http://www.rowtheboat.com/archives/37#comments" thr:count="7" />
		<link rel="replies" type="application/atom+xml" href="http://www.rowtheboat.com/archives/37/feed/atom" thr:count="7" />
		<thr:total>7</thr:total>
	<feedburner:origLink>http://www.rowtheboat.com/archives/37</feedburner:origLink></entry>
		<entry>
		<author>
			<name>george</name>
						<uri>http://</uri>
					</author>
		<title type="html"><![CDATA[SXSW]]></title>
		<link rel="alternate" type="text/html" href="http://feeds.rowtheboat.com/~r/Rowtheboat/~3/z2LO8ZSAgU8/36" />
		<id>http://www.rowtheboat.com/?p=36</id>
		<updated>2009-03-21T23:42:02Z</updated>
		<published>2009-03-21T23:41:29Z</published>
		<category scheme="http://www.rowtheboat.com" term="Uncategorized" /><category scheme="http://www.rowtheboat.com" term="sxsw" />		<summary type="html"><![CDATA[Thanks to a lucky draw at dConstruct last year I bagged two free tickets to this years SXSW.  I decided to invite Jim along for no other reason that he was likely to be the closest to the event.  I&#8217;d never been to Texas before and despite hearing many bad reports, word was [...]]]></summary>
		<content type="html" xml:base="http://www.rowtheboat.com/archives/36"><![CDATA[<p>Thanks to a lucky draw at <a href="http://dconstruct.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/dconstruct.org');">dConstruct</a> last year I bagged two free tickets to this years <a href="http://sxsw.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/sxsw.com');">SXSW</a>.  I decided to invite <a href="http://jamesbrady.wordpress.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/jamesbrady.wordpress.com');">Jim</a> along for no other reason that he was likely to be the closest to the event.  I&#8217;d never been to Texas before and despite hearing many bad reports, word was Austin really wasn&#8217;t quite as bad.</p>
<p>And what a surprise it was &#8211; a laid back city with fairly liberal attitudes.  Once I got over the English-American language barrier (swap line for queue, register for till and give me for can I have) things seemed to go well.  The line up of talks was amazing &#8211; Gary Vaynerchuk was awesome although sadly I only caught the last 20 minutes (<a href="http://events.carsonified.com/fowa/2009/miami/videos/gary-vaynerchuk" onclick="javascript:pageTracker._trackPageview('/outbound/article/events.carsonified.com');">good video of him here at FOWA</a>), Brian Brushwood did an excellent talk based on his <a href="http://revision3.com/scamschool/" onclick="javascript:pageTracker._trackPageview('/outbound/article/revision3.com');">scam school series</a>, <a href="http://en.wikipedia.org/wiki/James_Powderly" onclick="javascript:pageTracker._trackPageview('/outbound/article/en.wikipedia.org');">James Powderly</a> gave a fascinating talk of his grafitti art and getting detained in China, and there was an extremely useful panel on how to give good presentations.  That&#8217;s one of the parts I enjoyed the most &#8211; the sheer diversity of talks.  In addition there were more informal talks where the presenter started off for 10 minutes before opening up to the room &#8211; going freelance and becoming productive were two of my favourites in this format.  Of course due to the sheer volume of talks many good ones were missed &#8211; <a href="http://en.wikipedia.org/wiki/Larry_Lessig" onclick="javascript:pageTracker._trackPageview('/outbound/article/en.wikipedia.org');">Larry Lessig</a> seems the prime candidate here.  They&#8217;re going to make all the talks available for download so I&#8217;m looking forward to catching what I missed.</p>
<p>The talks are only half of Southby though.  The night life is great and there&#8217;s loads of parties with free drink and beer flowing.  These seemed quite hit and miss with the Digg party being awful and the <a href="http://twitter.com/goodgravy/status/1330461672" onclick="javascript:pageTracker._trackPageview('/outbound/article/twitter.com');">queue to get a signature from Kevin Rose</a> a really quite distressing sight.  But for every flop there were some good ones that provided entertainment as wide ranging as Burlesque and live photoshop drawing.</p>
<p>I met plenty of new interesting people, and bumped into quite a few from England although I know of least two out there who I didn&#8217;t bump into all week.  Other highlights included the weather, free wifi everywhere, a film called Burma VJ we randomly caught and England destroy France in the Rugby.  More random things included drive through banks and a gig featuring a hip-hop group I strangely enjoyed.  And the downers?  Well I can&#8217;t finish without digging just how awful the all american diet is (suprisingly I didn&#8217;t want my meal in a sea of melted cheese but gee thanks).  Overall though a great experience and well worth it if you&#8217;ve never made the trip.</p>
]]></content>
		<link rel="replies" type="text/html" href="http://www.rowtheboat.com/archives/36#comments" thr:count="2" />
		<link rel="replies" type="application/atom+xml" href="http://www.rowtheboat.com/archives/36/feed/atom" thr:count="2" />
		<thr:total>2</thr:total>
	<feedburner:origLink>http://www.rowtheboat.com/archives/36</feedburner:origLink></entry>
		<entry>
		<author>
			<name>george</name>
						<uri>http://</uri>
					</author>
		<title type="html"><![CDATA[Using objects in models (with CouchFoo)]]></title>
		<link rel="alternate" type="text/html" href="http://feeds.rowtheboat.com/~r/Rowtheboat/~3/-PoD-pk_qMo/35" />
		<id>http://www.rowtheboat.com/?p=35</id>
		<updated>2009-03-21T22:36:59Z</updated>
		<published>2009-03-21T22:36:59Z</published>
		<category scheme="http://www.rowtheboat.com" term="Uncategorized" /><category scheme="http://www.rowtheboat.com" term="couchfoo" /><category scheme="http://www.rowtheboat.com" term="rails" />		<summary type="html"><![CDATA[ActiveRecord allows you to serialize objects into text columns through YAML.  This seems useful but in my experience is under-used.  One of the primary reasons for this is it&#8217;s not possible to use the data that the object encapsulates without the ruby model.  For example it&#8217;s not possible to find on the [...]]]></summary>
		<content type="html" xml:base="http://www.rowtheboat.com/archives/35"><![CDATA[<p>ActiveRecord allows you to serialize objects into text columns through YAML.  This seems useful but in my experience is under-used.  One of the primary reasons for this is it&#8217;s not possible to use the data that the object encapsulates without the ruby model.  For example it&#8217;s not possible to find on the contents of that object or for that matter, modify the object with languages that lack YAML support.  With CouchDB all data is stored in JSON so this is not an issue.</p>
<p>The project I wrote CouchFoo for used complex ACLs and I wanted to encapsulate this all in an object rather than use several many-many relationships and construct an ACL object based on their contents.  So how do you this with CouchFoo?  Simple, any object can be assigned as a property in a CouchFoo model as long as it has a .to_json method and a class .from_json method.  The methods do what you&#8217;d expect, for example:</p>
<pre class="brush: ruby;">
class DataObjectAttributeList

  attr_accessor :attributes

  # Constructs the object from JSON
  def self.from_json(json)
    DataObjectAttributeList.new(json)
  end

  # Converts the object to JSON
  def to_json
    @attributes
  end

  def initialize(initials = {}, *args)
    @attributes = initials
  end
</pre>
<p>This is just a simple example storing a hash but the structure could be as complex as you&#8217;d like.  In the future I plan to add inline associations to CouchFoo, so rather than have a one-to-many association where the many are accessed via a second database query you could have the objects stored as part of the parent contents.  Performance wise, this is normally much more efficient (although not in all situations &#8211; eg heavy write and low read).</p>
<p>Overall, this becomes a very addictive way of developing and in the same way <a href="http://push.cx/2009/rules-of-database-app-aging" onclick="javascript:pageTracker._trackPageview('/outbound/article/push.cx');">you start to question whether you need a relational database</a>, you start to question whether you should store associated objects inline or separately.</p>
]]></content>
		<link rel="replies" type="text/html" href="http://www.rowtheboat.com/archives/35#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://www.rowtheboat.com/archives/35/feed/atom" thr:count="0" />
		<thr:total>0</thr:total>
	<feedburner:origLink>http://www.rowtheboat.com/archives/35</feedburner:origLink></entry>
		<entry>
		<author>
			<name>george</name>
						<uri>http://</uri>
					</author>
		<title type="html"><![CDATA[CouchFoo: ActiveRecord styled API for CouchDB]]></title>
		<link rel="alternate" type="text/html" href="http://feeds.rowtheboat.com/~r/Rowtheboat/~3/Wwrl8Ou3OeA/33" />
		<id>http://www.rowtheboat.com/?p=33</id>
		<updated>2009-03-06T07:54:37Z</updated>
		<published>2009-02-04T11:25:44Z</published>
		<category scheme="http://www.rowtheboat.com" term="Uncategorized" /><category scheme="http://www.rowtheboat.com" term="activerecord" /><category scheme="http://www.rowtheboat.com" term="couchdb" /><category scheme="http://www.rowtheboat.com" term="couchfoo" /><category scheme="http://www.rowtheboat.com" term="rails" />		<summary type="html"><![CDATA[CouchDB is an excellent database, designed especially for distributed applications.  To quote the official site site:
Apache CouchDB is a distributed, fault-tolerant and schema-free document-oriented database accessible via a RESTful HTTP/JSON API. Among other features, it provides robust, incremental replication with bi-directional conflict detection and resolution, and is queryable and indexable using a table-oriented view [...]]]></summary>
		<content type="html" xml:base="http://www.rowtheboat.com/archives/33"><![CDATA[<p>CouchDB is an excellent database, designed especially for distributed applications.  To quote the <a href="http://couchdb.apache.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/couchdb.apache.org');">official site</a> site:</p>
<blockquote><p>Apache CouchDB is a distributed, fault-tolerant and schema-free document-oriented database accessible via a RESTful HTTP/JSON API. Among other features, it provides robust, incremental replication with bi-directional conflict detection and resolution, and is queryable and indexable using a table-oriented view engine with JavaScript acting as the default view definition language.</p></blockquote>
<p>along with the knowledge it&#8217;s written in Erlang, you know it&#8217;s going to go be a winner in the future.</p>
<p><img class="alignleft size-medium wp-image-29" src="http://www.rowtheboat.com/wp-content/uploads/2009/02/couchdb.png" alt="CouchDB logo" align="left" /> For one of my current freelance projects I needed to store data in a document fashion &#8211; ie unstructured.  This made CouchDB an ideal candidate.  There were several ruby gems available: CouchPotato, CouchREST, ActiveCouch and RelaxDB gems. Each offered its own benefits and own challenges. After hacking with each I couldn’t get a library was happy with. So I started with ActiveRecord and modified it to work with CouchDB. And so <a href="http://github.com/georgepalmer/couch_foo" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">CouchFoo</a> was born.</p>
<p>In the end I ended up with a gem that mirrors ActiveRecord in all but a few minor places.  In particular:</p>
<ul>
<li>CouchDB is schema free so property defintions for the document are defined in the model (like DataMapper)</li>
<li>:select, :joins, :having, :group, :from and :lock are not available on find or associations as they don’t apply (locking is handled as conflict resolution at insertion time)</li>
<li>:conditions can only accept a hash and not an array or SQL. For example :conditions =&gt; {:user_name =&gt; &#8220;Georgio_1999&#8243;}</li>
<li>:offset is less efficient in CouchDB &#8211; there’s more on this in the rdoc</li>
<li>:order is applied after results are retrieved from the database. Therefore :order cannot be used with :limit without a new option :use_key. This is explained fully in the quick start guide and CouchFoo#find documentation</li>
<li>:include isn’t implemented yet but the finders and associations still accept the option so you won’t need to make any code changes</li>
<li>By default results are ordered by document key. The key uses a UUID scheme so these don’t auto-increment and are likely to come out in a different order to insertion. default_sort can be used on a model to sort by create date by default and overcome this</li>
<li>validates_uniqueness_of has had the :case_sensitive option removed</li>
<li>Because there’s no SQL there’s no SQL finder methods</li>
<li>Timezones, aggregations and fixtures are not yet implemented</li>
<li>The price of index updating is paid when next accessing the index rather than the point of insertion. This can be more efficient or less depending on your application. It may make sense to use an external process to do the updating for you &#8211; see CouchFoo#find for more on this</li>
<li>On that note, occasional compacting of CouchDB is required to recover space from old versions of documents and keep performance high. This can be kicked off in several ways (see quick start guide)</li>
</ul>
<p>The RDoc for the gem contains more details on each of these differences, new features that I added, a quick start guide and additional areas of responsibility to think about when using CouchDB (in particular performance).</p>
<p>As a quick overview, basic operations are the same as ActiveRecord:</p>
<pre class="brush: ruby;">
class Address &lt; CouchFoo::Base
property :number, Integer
property :street, String
property :postcode # Any generic type is fine as long as .to_json can be called on it
end
</pre>
<pre class="brush: ruby;">
address1 = Address.create(:number =&gt; 3, :street =&gt; &quot;My Street&quot;, :postcode =&gt; &quot;secret&quot;) # Create address
address2 = Address.create(:number =&gt; 27, :street =&gt; &quot;Another Street&quot;, :postcode =&gt; &quot;secret&quot;)
Address.all # = [address1, address2] or maybe [address2, address2] depending on key generation
Address.first    # = address1 or address2 depending on keys so probably isn't as expected
Address.find_by_street(&quot;My Street&quot;) # = address1
</pre>
<p>As key generation is through a UUID scheme, the order can&#8217;t be predicted. However you can order the results by default:</p>
<pre class="brush: ruby;">
class Address &lt; CouchFoo::Base
property :number, Integer
property :street, String
property :postcode # Any generic type is fine as long as .to_json can be called on it
property :created_at, DateTime

default_sort :created_at
end
</pre>
<pre class="brush: ruby;">
Address.all # = [address1, address2]
Address.first    # = address1 or address2, sorting is applied after results
Address.first(:use_key =&gt; :created_at) # = address1 but at the price of creating a new index
</pre>
<p>Note that there&#8217;s an optimisation that will order results by created_at if there are no conditions so in the above case, the default_sort wasn&#8217;t required.  However when using with conditions it will be required so it makes sense to use at all times.</p>
<p>Conditions work slightly differently:</p>
<pre class="brush: ruby;">
Address.find(:all, :conditions {:street =&gt; &quot;My Street&quot;}) # = address1, creates index on :street
Address.find(:all, :conditions {:created_at =&gt; &quot;sometime&quot;}) # Uses same index as :use_key =&gt; :created_at
Address.find(:all, :use_key =&gt; :street, :startkey =&gt; 'p') # All streets from p in alphabet, reuses the index created 2 lines up
</pre>
<p>As well as providing support for people using relational databases, CouchFoo attempts to provide a library for those wanting to use CouchDB as a document-orientated database:</p>
<pre class="brush: ruby;">
class Document &lt; CouchFoo::Base
property :number, Integer
property :street, String

view :number_ordered, &quot;function(doc) {emit([doc.number , doc.street], doc); }&quot;, nil, :descending =&gt; true
end
</pre>
<pre class="brush: ruby;">
Document.number_ordered(:limit =&gt; 75) # Will get the last 75 documents in the database ordered by number, street attributes
</pre>
<p>Associations work as expected but you must to remember to add the properties required for an association (we’ll make this automatic soon):</p>
<pre class="brush: ruby;">
class House &lt; CouchFoo::Base
has_many :windows
end

class Window &lt; CouchFoo::Base
property :house_id, String
belongs_to :house
end
</pre>
<p>There&#8217;s a few bits left to tidy up (as noted in the readme) but generally speaking it&#8217;s now ready for use by others.  Grab it on <a href="http://github.com/georgepalmer/couch_foo" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">github</a> and feel free to fork and send me pull requests.</p>
<p>And now to do something I&#8217;ve not being doing a lot of lately, spend some more time on the Couch&#8230;</p>
]]></content>
		<link rel="replies" type="text/html" href="http://www.rowtheboat.com/archives/33#comments" thr:count="4" />
		<link rel="replies" type="application/atom+xml" href="http://www.rowtheboat.com/archives/33/feed/atom" thr:count="4" />
		<thr:total>4</thr:total>
	<feedburner:origLink>http://www.rowtheboat.com/archives/33</feedburner:origLink></entry>
		<entry>
		<author>
			<name>george</name>
						<uri>http://</uri>
					</author>
		<title type="html"><![CDATA[Rails with Datamapper]]></title>
		<link rel="alternate" type="text/html" href="http://feeds.rowtheboat.com/~r/Rowtheboat/~3/HV7RAXjmhsA/32" />
		<id>http://www.rowtheboat.com/?p=32</id>
		<updated>2009-04-15T14:25:25Z</updated>
		<published>2009-01-08T20:34:48Z</published>
		<category scheme="http://www.rowtheboat.com" term="Uncategorized" /><category scheme="http://www.rowtheboat.com" term="datamapper" /><category scheme="http://www.rowtheboat.com" term="rails" />		<summary type="html"><![CDATA[With the recent announcement that Rails and MERB will merge and my preference for DataMapper I decided to plug datamapper into rails for my next freelance project.  The theory goes this should make the upgrade path to Rails 3 a lot simpler!
It&#8217;s currently possible to use Datamapper with Rails, heck even DHH himself commented [...]]]></summary>
		<content type="html" xml:base="http://www.rowtheboat.com/archives/32"><![CDATA[<p>With the recent announcement that <a href="http://weblog.rubyonrails.org/2008/12/23/merb-gets-merged-into-rails-3" onclick="javascript:pageTracker._trackPageview('/outbound/article/weblog.rubyonrails.org');">Rails and MERB will merge</a> and my preference for <a href="http://datamapper.org" onclick="javascript:pageTracker._trackPageview('/outbound/article/datamapper.org');">DataMapper</a> I decided to plug datamapper into rails for my next freelance project.  The theory goes this should make the upgrade path to Rails 3 a lot simpler!</p>
<p>It&#8217;s currently possible to use Datamapper with Rails, heck even <a href="http://loudthinking.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/loudthinking.com');">DHH</a> himself commented so, but it&#8217;s not quite easy as using ActiveRecord.  After a quick Google I only ran into question of how to do it, no howto guide.  So I set out to make mine own &#8211; it really was quite simple in the end:</p>
<pre class="brush: ruby;">
sudo gem install addressable data_objects do_mysql
# do_mysql can be changed for do_postgres or do_sqlite3 as appropriate
sudo gem install dm-core dm-more
</pre>
<p>In the <a href="http://github.com/datamapper/dm-more/tree/master" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">dm-more github repos</a> there&#8217;s a folder called rails_datamapper which is a plugin for rails to add datamapper support.  This doesn&#8217;t install with the dm-more gem so it&#8217;s a case of cloning the git repository and copy the folder to your rails project:</p>
<pre class="brush: ruby;">
git clone git://github.com/sam/dm-more.git
cp -R dm-more/rails_datamapper /vendor/plugins
</pre>
<p>Then edit your project environment.rb file and add the following lines:</p>
<pre class="brush: ruby;">
# Load the required gems in the correct order
config.gem &quot;addressable&quot;, :lib =&gt; &quot;addressable/uri&quot;
config.gem &quot;data_objects&quot;
config.gem &quot;do_mysql&quot;
config.gem &quot;dm-core&quot;

# Make datamapper load first as some plugins have dependencies on it
config.plugins = [ :rails_datamapper, :all ]

# Remove ActiveRecord if you no longer need it
config.frameworks -= [ :active_record ]
</pre>
<p>The connection to the database will be made by the rails_datamapper plugin using your database.yml configuration file.  You&#8217;ll need to use a slightly different format for datamapper:</p>
<pre class="brush: ruby;">
development:
:repositories:
:adapter: mysql
:database: opnli_dev
</pre>
<p>Or alternately you can specify your own initializer and forgo the rails plugin:</p>
<pre class="brush: ruby;">
hash = YAML.load(File.new(RAILS_ROOT + &quot;/config/database.yml&quot;))
DataMapper.setup(:default, hash[RAILS_ENV])
</pre>
<p>The only real gotcha in using datamapper is some rails plugins assume you&#8217;re using ActiveRecord.  Hopefully this won&#8217;t be the case in the future, but for now you&#8217;ll need to get forking!</p>
]]></content>
		<link rel="replies" type="text/html" href="http://www.rowtheboat.com/archives/32#comments" thr:count="5" />
		<link rel="replies" type="application/atom+xml" href="http://www.rowtheboat.com/archives/32/feed/atom" thr:count="5" />
		<thr:total>5</thr:total>
	<feedburner:origLink>http://www.rowtheboat.com/archives/32</feedburner:origLink></entry>
		<entry>
		<author>
			<name>george</name>
						<uri>http://</uri>
					</author>
		<title type="html"><![CDATA[Git]]></title>
		<link rel="alternate" type="text/html" href="http://feeds.rowtheboat.com/~r/Rowtheboat/~3/Oiln0cAIgdM/31" />
		<id>http://www.rowtheboat.com/?p=31</id>
		<updated>2008-12-21T17:46:15Z</updated>
		<published>2008-12-21T17:46:15Z</published>
		<category scheme="http://www.rowtheboat.com" term="Uncategorized" /><category scheme="http://www.rowtheboat.com" term="git" /><category scheme="http://www.rowtheboat.com" term="rails" /><category scheme="http://www.rowtheboat.com" term="scm" />		<summary type="html"><![CDATA[For those readers of my blog who don&#8217;t live in the rails world I highly recommend checking out Git, a distributed version control system.  It has been big in the rails world since early this year for several good reasons:

It has distributed and offline functionality
Making and merging branches is a breeze &#8211; encouraging you [...]]]></summary>
		<content type="html" xml:base="http://www.rowtheboat.com/archives/31"><![CDATA[<p>For those readers of my blog who don&#8217;t live in the rails world I highly recommend checking out <a href="http://git.or.cz/" onclick="javascript:pageTracker._trackPageview('/outbound/article/git.or.cz');">Git</a>, a distributed version control system.  It has been big in the rails world since early this year for several good reasons:</p>
<ul>
<li>It has distributed and offline functionality</li>
<li>Making and merging branches is a breeze &#8211; encouraging you to try experiments in branches</li>
<li>It uses much less space than alternatives, such as Subversion, and only has one .git folder at the base of your project</li>
<li>It&#8217;s in active development with constant releases of new features (but stable enough to be used for the linux kernel)</li>
</ul>
<p>The terminology is slightly different from subversion and friends but once you&#8217;ve got used to it you never look back!</p>
<p><a href="http://merbivore.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/merbivore.com');">Merb</a> was very quick to jump on the git bandwagon and <a href="http://rubyonrails.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/rubyonrails.org');">rails</a> followed not much later.  Practically this made distributed development a hell of a lot easier, but it also had some nice knock on effects.  Patching is now a lot quicker too &#8211; you simply fork the project, make a fix and inform the admin who can then choose to merge back into the master (if they see fit).  It&#8217;s made the process for fixing bugs a hell of a lot quicker.</p>
<p>Soon after git came along the fantastic <a href="http://github.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">github.com</a> followed making it easy to host remote repositories.  And so to the reason for me writing this post &#8211; github <a href="http://github.com/blog/272-github-pages" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">just launched git pages</a> where you can upload your own page to front your repositories.  It&#8217;s a neat idea and naturally is all managed through a git repository.  You simply create your site in a repository, push to github and the deployment is automatic.  Although it&#8217;s only simple HTML pages, it&#8217;s a great proof of concept of other things that could be possible.  <a href="http://georgepalmer.github.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/georgepalmer.github.com');">My effort can be found here</a> which following the git ethos I just forked from <a href="http://schacon.github.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/schacon.github.com');">somebody else</a></p>
]]></content>
		<link rel="replies" type="text/html" href="http://www.rowtheboat.com/archives/31#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://www.rowtheboat.com/archives/31/feed/atom" thr:count="0" />
		<thr:total>0</thr:total>
	<feedburner:origLink>http://www.rowtheboat.com/archives/31</feedburner:origLink></entry>
		<entry>
		<author>
			<name>george</name>
						<uri>http://</uri>
					</author>
		<title type="html"><![CDATA[Ruby Manor]]></title>
		<link rel="alternate" type="text/html" href="http://feeds.rowtheboat.com/~r/Rowtheboat/~3/vkHSydXHMZI/28" />
		<id>http://www.rowtheboat.com/?p=28</id>
		<updated>2009-03-06T10:10:25Z</updated>
		<published>2008-11-23T15:38:14Z</published>
		<category scheme="http://www.rowtheboat.com" term="Uncategorized" /><category scheme="http://www.rowtheboat.com" term="nanite" /><category scheme="http://www.rowtheboat.com" term="presentation" /><category scheme="http://www.rowtheboat.com" term="ruby" /><category scheme="http://www.rowtheboat.com" term="rubymanor" />		<summary type="html"><![CDATA[ Yesterday I spoke at and attended Ruby Manor.  It was a grass route conference with the attendees determining the agenda and the organising duo aiming to keep costs to an absolute minimum.  So successful were they infact, and as one twitterer aptly points out, that for an amazing £12 you got a [...]]]></summary>
		<content type="html" xml:base="http://www.rowtheboat.com/archives/28"><![CDATA[<p><a href="http://www.rowtheboat.com/wp-content/uploads/2008/11/frame.png" ><img class="alignleft size-medium wp-image-29" src="http://www.rowtheboat.com/wp-content/uploads/2008/11/frame-150x150.png" alt="Ruby Manor Frame" width="150" height="150" align="left" /></a> Yesterday I spoke at and attended <a href="http://rubymanor.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/rubymanor.org');">Ruby Manor</a>.  It was a grass route conference with the attendees determining the <a href="http://rubymanor.org/schedule/" onclick="javascript:pageTracker._trackPageview('/outbound/article/rubymanor.org');">agenda</a> and the <a href="http://www.h-lame.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.h-lame.com');">organising</a> <a href="http://interblah.net/" onclick="javascript:pageTracker._trackPageview('/outbound/article/interblah.net');">duo</a> aiming to keep costs to an absolute minimum.  So successful were they infact, and as one twitterer aptly <a href="http://twitter.com/kerryb/status/1018588591" onclick="javascript:pageTracker._trackPageview('/outbound/article/twitter.com');">points out</a>, that for an amazing £12 you got a series of excellent talks, no annoying sponsorship and £500 behind the bar at the end of the night.  Given even the <a href="http://2008.dconstruct.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/2008.dconstruct.org');">cheapest of conferences</a> aimed at freelancers clocks in well over the £100 mark, this really was a fantastic achievement.</p>
<p>On a personal note I presented on <a href="http://github.com/ezmobius/nanite/tree/master" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">nanite</a> which is a background processing solution for rails and merb.  It was quite a technical talk and I was trying to get a lot into the 30 minutes timeslot, so it felt a little rushed.  Nevertheless most people seemed to grab the concept and the live demo at the end went really well.  For those that missed the event I&#8217;m sure the videos will be online soon, but in the meantime there&#8217;s an excellent coverage on this <a href="http://effectif.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/effectif.com');">blog</a> and the slides from my presentation are available on <a href="http://www.slideshare.net/Georgio_1999/rubymanor-presentation/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.slideshare.net');">slideshare</a> or below:</p>
<object width="425" height="348"><param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=rubymanor-1227366017327827-9"/><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=rubymanor-1227366017327827-9"  type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="348"></embed></object><!-- ysttest:Array
(
    [id] => 777917&amp;doc=rubymanor-1227366017327827-9
)
-->
]]></content>
		<link rel="replies" type="text/html" href="http://www.rowtheboat.com/archives/28#comments" thr:count="1" />
		<link rel="replies" type="application/atom+xml" href="http://www.rowtheboat.com/archives/28/feed/atom" thr:count="1" />
		<thr:total>1</thr:total>
	<feedburner:origLink>http://www.rowtheboat.com/archives/28</feedburner:origLink></entry>
		<entry>
		<author>
			<name>george</name>
						<uri>http://</uri>
					</author>
		<title type="html"><![CDATA[New plugins]]></title>
		<link rel="alternate" type="text/html" href="http://feeds.rowtheboat.com/~r/Rowtheboat/~3/5FN7FJM-6z0/27" />
		<id>http://www.rowtheboat.com/?p=27</id>
		<updated>2008-09-26T17:21:06Z</updated>
		<published>2008-09-26T17:21:06Z</published>
		<category scheme="http://www.rowtheboat.com" term="Uncategorized" /><category scheme="http://www.rowtheboat.com" term="caching" /><category scheme="http://www.rowtheboat.com" term="defensio" /><category scheme="http://www.rowtheboat.com" term="plugins" /><category scheme="http://www.rowtheboat.com" term="rails" />		<summary type="html"><![CDATA[I&#8217;ve just pushed two plugins to github.  The first is an improvement on the standard Defensio plugin that only checks the validity of your API key when posting articles or comments.  This is better than checking each time a model that uses the plugin is instantiated as it doesn&#8217;t require contact with the [...]]]></summary>
		<content type="html" xml:base="http://www.rowtheboat.com/archives/27"><![CDATA[<p>I&#8217;ve just pushed two plugins to github.  The <a href="https://github.com/GeorgePalmer/defensio/tree" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">first</a> is an improvement on the standard <a href="http://defensio.com/" onclick="javascript:pageTracker._trackPageview('/outbound/article/defensio.com');">Defensio</a> plugin that only checks the validity of your API key when posting articles or comments.  This is better than checking each time a model that uses the plugin is instantiated as it doesn&#8217;t require contact with the Defensio API (so is faster) and also won&#8217;t bring your site to a standstill if someone is just viewing a page and the Defensio service is down.</p>
<p>The <a href="https://github.com/GeorgePalmer/timed_fragment_cache/tree" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">second</a> updates the highly useful <a href="http://livsey.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/livsey.org');">timed fragment cache plugin</a> by Richard Livsey to support Rails 2.1</p>
]]></content>
		<link rel="replies" type="text/html" href="http://www.rowtheboat.com/archives/27#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://www.rowtheboat.com/archives/27/feed/atom" thr:count="0" />
		<thr:total>0</thr:total>
	<feedburner:origLink>http://www.rowtheboat.com/archives/27</feedburner:origLink></entry>
	</feed><!-- Dynamic Page Served (once) in 0.860 seconds --><!-- Cached page served by WP-Cache -->
