We are a software consultancy based in Berlin, Germany. We deliver
high quality web apps in short timespans.

Upstream Agile GmbH Logo

Couch Potato unleashed - a couchdb persistence layer in ruby (updated)

October 27, 2008 by alex

Update: the gem is now available, see the installation instructions below.

After several weeks of incubating on my computer it’s finally time to get real: I have just open sourced Couch Potato under the MIT license. You can get Couch Potato on github now. For an introduction to CouchDB and ruby please read my previous blog post A CouchDB primer for an ActiveRecord mindset. The following is a very short introduction into using Couch Potato. If you want to know more you can start with the README.

The goal of Couch Potato is to create a migration path for users of ActiveRecord and other object relational mappers to port their applications to CouchDB. It therefore offers a basic set of the functionality provided by most ORMs and adds functionality unique to CouchDB on top.

Installation

Couch Potato is available as a gem from http://gems.github.com, so you can just do

$ sudo gem source --add http://gems.github.com # if you haven't alread

$ sudo gem install langalex-couch_potato

$ irb
>> require 'rubygems'
>> gem 'couch_potato'
>> require 'couch_potato'
>> CouchPotato::Config.database_name = 'name of the db'

Alternatively you can download the sources from github. If you are using rails just copy the files into vendor/plugins, create a RAILS_ROOT/config/couchdb.yml file (see the README for the format) and you are ready to go. For other applications you will have to require the lib/couch_potato.rb file and then set the database name by calling CouchPotato::Config.database_name = 'name of the db'.

As Couch Potato is still very young you can expect its feature set to grow quite a bit in the near future. What you can download now is the very core together with a few features giving you a glimpse of what is about to come:

Persistence

Create a new class and make its instances persistable by including the Persistence module. As there is no schema in a CouchDB you have to declare the properties you want to persist:

class User
  include CouchPotato::Persistence

  property :name
end

Now you can save your objects:

user = User.new :name => 'joe'
user.save # or save!

Properties:

user.name # => 'joe'

user.name = {:first => ['joe', 'joey'], :last => 'doe', :middle => 'J'} # you can set any ruby object that responds_to :to_json

user._id # => "02097f33a0046123f1ebc0ebb6937269"

user.created_at # => Fri Oct 24 19:05:54 +0200 2008

You can of course also retrieve your instance:

User.get "02097f33a0046123f1ebc0ebb6937269" # => < #User 0x3075>

Associations

As of now has_many and belongs_to are supported. By default the associated objects are stored in separate documents linked via foreign keys just like in relational databases.

class User
  has_many :addresses, :dependent => :destroy
end

class Address
  belongs_to :user
  property :street
end

user = User.new
user.addresses.build :street => 'potato way'
user.addresses.first # => < #Address 0x987>

user.addresses.create! # raises an exception as street is blank

user.addresses.first.user == user # => true

When saving an object all associated objects are automatically saved as well. All these save operations are sent to CouchDB in one operation which means the whole process is atomic across all objects saved, plus only one database roundtrip is required making it much faster.

As CouchDB can not only store flat structures you also store associations inline:

class User
  has_many :addresses, :stored => :inline
end

This will store the addresses of the user as an array within your CouchDB document.

Callbacks

Couch Potato supports the usual lifecycle callbacks known from ActiveRecord:

class User
  include CouchPotato::Persistence

  before_create :do_something_before_create
  after_update :do_something_else
end

Versioning

Couch Potato supports versioning your objects, very similar to the popular acts_as_versioned plugin for ActiveRecord. To use it include the module:

class Document
  include CouchPotato::Persistence
  include CouchPotato::Versioning
end

After that your object will have a version that gets incremented on each save.

doc = Document.create
doc.version # => 1

doc.save
doc.version # => 2

You can access the older versions via the versions method.

doc.versions.first.version # => 1

When passing a version number the version method will only return that version:

doc.versions(1).version # => 1

Ordered Lists

Couch Potato supports ordered lists for has_many relationships (with the :stored => :separately option only), very similar to the popular acts_as_list plugin for ActiveRecord. To use it include the module:

class PersistenArray
  include CouchPotato::Persistence
  has_many :items
end

class Item
  include CouchPotato::Ordering
  belongs_to :persistent_array
  set_ordering_scope :persistent_array_id
end

array = PersistenArray.new
item1 = array.items.create!
item1.position # => 1

item2 = array.items.create!
item2.position # => 2

You can move items up and down simply by changing the position:

item2.position = 1
item2.save!
item1.position # => 2

Conclusion

Couch Potato is very young and it’s open source, so if you find any bugs (you most definitely will) please go to the bug tracker and file a ticket. If you want to contribute please create a fork on github. If you have ideas for improvements please email me or comment on this post.

Hello Explorer!

You’ve found our very old Website Archive (2007-2012). It’s a bit out of date, but we love looking back at how it all started - and how far we’ve come since then! We’re now fully focused on building our coworking management product, Cobot.

Take a look →