Here's Looking At You, Child.

RSS
Feb 8

Easy document revisions with RelaxDB

I’ve been using CouchDB/RelaxDB for a project I’m working on, and I wanted an easy way to access CouchDB’s document versioning for my models. Here’s what I came up with.

Without going into too much detail, CouchDB doesn’t update documents in place, instead it creates a new document with the same ID and a new revision string. This gives you access to a rudimentary versioning system (which they warn you not to rely on, BTW.)

This functionality is perfect for the project I’m working on, which runs some tests at a regular interval and stores the results in CouchDB. I can then generate nice graphs based on the history of each object, so i can see how these test results have changed over time.

I messed with RelaxDB for Ruby for a little while to get this whole revisiony thing to work. For those familiar with RelaxDB, it exposes RelaxDB.load(_id, :revs=>true) for you, but due to limitations in Couch, you can’t get the :revs from a view, only directly loading an object. So to get around this, I mixed a revisions method into the Document class:

$YOUR_PROJECT/relaxdb/revisions.rb:
module RelaxDB

  class Document
    property :_revisions
    property :_revs_info

    def revisions(params={})
      RelaxDB.load(self._id,:revs_info=>true)._revs_info.collect do |rev|
        RelaxDB.load(self._id, :rev=>rev['rev']) if rev['status'] == 'available'
      end
    end

  end

end

Now, inside of your models.rb, you can just include it:

$YOUR_PROJECT/models.rb:
 
require 'relaxdb'
require 'relaxdb/revisions'
class MyModel < RelaxDB::Document
  property :name
  property :description
  view_by :name
end 

And then you can simply do this:

>> mm = MyModel.new(:name=>'Thing One')
=> #<MyModel:2165734660, _id: "96579a10-f749-012c-7654-001b63ac5fc7", name: "Thing One">
>> mm.save!
=> #<MyModel:2165734660, _id: "96579a10-f749-012c-7654-001b63ac5fc7", _rev: "1-160033dfbccd3327ffcffe94e5cd63f8", name: "Thing One">
>> mm.name = 'Changed Thing'
=> "Changed Thing"
>> mm.save!
=> #<MyModel:2165734660, _id: "96579a10-f749-012c-7654-001b63ac5fc7", _rev: "2-8a95904a579942d6add4fd9e7b272165", name: "Changed Thing">
>> mm.revisions
=> [#<MyModel:2165559880, _id: "96579a10-f749-012c-7654-001b63ac5fc7", _rev: "2-8a95904a579942d6add4fd9e7b272165", name: "Changed Thing">, #<MyModel:2165545120, _id: "96579a10-f749-012c-7654-001b63ac5fc7", _rev: "1-160033dfbccd3327ffcffe94e5cd63f8", name: "Thing One">]

Nifty!