No commit activity in last 3 years
A Rails plugin to read and write CouchDB documents via Activerecord
 Dependencies
 Project Readme

Stuffing

Stuffing is a Rails plugin that allows you to really easily add CouchDB documents to existing ActiveRecord models.

I love CouchDB and I love the principles behind it. I love the flexibility of a ‘schemaless’ document, crash-only architecture and single file databases.

After prototyping a few apps using CouchDB however, I found that I was trying to bend CouchDB around corners that it just didn’t fit. There are so many great things that have been developed around ActiveRecord that I take for granted every day. Plugins that ‘just work’ like will_paginate, Paperclip, ThinkingSphinx.

Still, from playing around with CouchDB, I found myself missing some of the things from my experiments with it. Just adding a form field to a form and getting a per-record field. It’s really nice.

And so: Stuffing. Stuffing bridges the gap between building a completetly “ActiveRecord aware” or “ActiveRecord like” wrapper around CouchDB and simply adding the ability to add a “CouchDB” store to an existing ActiveRecord model.

Stick around to see how it works.

Requirements

CouchDB
You can install CouchDB via the CouchDB website:
http://couchdb.apache.org/downloads.html

CouchRest
Stuffing accesses CouchDB via jchris’s CouchRest gem.


  sudo gem sources -a http://gems.github.com
  sudo gem install jchris-couchrest

Installation

Stuffing is a Ruby on Rails plugin. Installation is as easy as:


  ./script/plugin install git://github.com/paulca/stuffing.git

Example


class Post < ActiveRecord
  stuffing
end

That’s all you need to get going. This enables Stuffing by adding a ‘stuffing’ method to your ActiveRecord model. This method is a hash that will be persisted in CouchDB after you save or update your model. Post, above, is just a regular old ActiveRecord model, with a “posts” table and maybe a few fields. They all still work as normal, but you get a new magic “stuffing” attribute. This can contain whatever you want and it can change record to record. CouchDB doesn’t care what you stuff into it.

By default, Stuffing will connect to CouchDB on http://localhost:5984. It will use or create a CouchDB database the same name as your Rails app, as defined by your RAILS_ROOT folder and your current environment. For example, if your RAILS_ROOT were /var/www/stuffing_app in production environment, by default Stuffing would use stuffing_app_development as the DB name. Documents are stored with an ID of “Class-ID”, so for the example “Post” model above, document IDs in CouchDB would be “Post-1”, “Post-2”. “Post-3” etc.

To save attributes, you can treat your ‘stuffing’ method like any other ActiveRecord attribute. Just assign a hash to your “stuffing” method:


  @post = Post.new
  @post.stuffing = {:title => 'Fantastic', :description => 'this is an example post'}
  @post.save

The stuffing method can take any hash you want, which will be saved to CouchDB as JSON. Simple types (Strings, Integers etc. will be preserved. See the CouchRest documentation for more on how this works)

Your stuffing is retrieved when you load your posts via ActiveRecord:


  @post = Post.first
  @post.stuffing
  => {:title=>"Fantastic", :description=>"this is an example post"}
  @post.update_attributes(:stuffing => {:title => 'New stuffing title'})

Stuffing also gives you access (via method_missing, I know, I’m sorry) to an unlimited supply of attributes, for assigning and retrieving from your Couch document:


  @post = Post.first
  @post.stuffing_new_title = "A magic new title"
  @post.stuffing_other_attribute = "Tasty"
  
  @post.stuffing_new_title
  => "A magic new title"
  
  @post.stuffing_other_attribute
  => "Tasty"
  
  @post.stuffing
  => {'new_title' => "A magic new title", 'other_attribute' => "Tasty"}

Options

A sensible set of defaults should let you get up and running with Stuffing / CouchDB straight away, but the real magic of CouchDB is that you can really easily connect to multiple databases as everything is done over HTTP. Stuffing accepts a few configuration variables to dynamically choose host / database and even documents.

You can specify a different method name for your stuffing:


  class Post < ActiveRecord
    stuffing :contents
  end

This will give you @post.contents instead of @post.stuffing

You can also dynamically choose the host, database and Couch document ID. You can call any method, or method chain, prefixed by ‘:’
(inspired by the interpolated path and url strings in Paperclip)


  class Blog < ActiveRecord
  end
  class Post < ActiveRecord
    belongs_to :blog
    stuffing :host => ':couch_host.example.com', :port => '1234', :database => 'blog-:blog.id', :id => ':class-:id-:locale'
    
    def locale
      ['en', 'fr'].rand
    end
    
    def couch_host
      'subdomain'
    end
  end

This will connect, for example, to the ‘blog-1’ database on http://subdomain.example.com on port 1234, saving the stuffing document as ‘Post-1-en’ or ‘Post-1-fr’ depending on the result of the ‘locale’ method.

What about CouchDB views?

Stuffing completely sidesteps CouchDB views for now. While views are one of the most powerful components of CouchDB, they are also the most difficult to get the head around. Stuffing uses MySQL to pull in records and create relationships between tables. It GETs and POSTs to CouchDB to retrieve and save documents. While there may be extra power by integrating views at a later stage, Stuffing gently gets you up and running by ignoring views completely.

What’s next

From where I see it, this is a lot of fun and potentially kind of powerful. The plugin is well tested for basic usage. It’s not, however, in any way optimised for performance.

There’s probably a lot wrong with mixing MySQL and CouchDB in this way. What this plugin is, however, is a really quick, really easy way of adding some of the most powerful features of CouchDB to your app without leaving the save, fluffy familiar world of MySQL / ActiveRecord behind.

About me

I’m Paul Campbell. I’m a partner in Contrast (http://www.contrast.ie) and I work on Exceptional, a Ruby on Rails exception tracker (http://getexceptional.com).

Follow me on Twitter http://twitter.com/paulca

Copyright © 2009 Paul Campbell, released under the MIT license