DataMapper plugin enabling simple versioning of models
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



DataMapper plugin enabling simple versioning of models.

When a model is versioned, and updated, instead of the previous version being lost in the mists of time, it is saved in a subsidiary table, so that it can be restored later if needed.

Please Note! this gem behaves differently to how AR's :acts_as_versioned works. There is currently no multi version storage possible.



Install the dm-is-versioned gem.

$ (sudo)? gem install dm-is-versioned


Download or clone dm-is-versioned from Github.

$ cd /path/to/dm-is-versioned

$ rake install            # will install dm-is-versioned

Getting started

To start using this gem, just require dm-is-versioned in your app.

Lets say we have a Post class, and we want to retain the previous version of a post. Just do this:

class Post
  include DataMapper::Resource

  property :id,         Serial
  property :title,      String
  property :body,       Text
  property :updated_at, DateTime

  is_versioned :on => :updated_at

  ## this syntax also works
  # is :versioned, :on => :updated_at


That simple snippet will automatically create a second Post::Version model and a (post_versions) table in your DB when you auto migrate or auto upgrade:

Post.auto_migrate! # => will run auto_migrate! on Post::Version, too
Post.auto_upgrade! # => will run auto_upgrade! on Post::Version, too

# or
DataMapper.auto_migrate! # => will run auto_migrate! on Post::Version, too
DataMapper.auto_upgrade! # => will run auto_upgrade! on Post::Version, too

# don't forget to require 'dm-migrations' before you migrate.

OK, now that we have a versioned model, let's see what we can do with it.


We start with creating a new Post:

post = Post.create(:title => 'A versioned Post title', :body => "A versioned Post body")
# automatically saved

When we create this Post, no secondary version is created.

The versioning only takes place when we update our Post:

post.title = "An updated & versioned Post title"

In the Post::Version (post_versions) table we would now find the previous version of the Post.

This is how it would look like:

# table
| id | title                                | body                       | updated_at |
| 1 | 'An updated & versioned Post title'   | 'A versioned Post body'    | DateTime   |

# db.post_versions table
| id | title                                | body                       | updated_at |
| 1 | 'A versioned Post title'              | 'A versioned Post body'    | DateTime   |


Once you have a versioned model, you can retrieve the previous version, like this:

old_post = post.versions.first
  => #<Post::Version @id=1 @title="A versioned Post title" @body=... @updated_at=...>

Please Note! that the #versions method returns an array by default.

That's basically what dm-is-versioned does.


Now there are some gotcha's that might not be entirely obvious to everyone, so let's clarify them here.

Make sure the versioned trigger has a value

In this type of scenario:

class Post
  property :updated_at, DateTime

  is_versioned :on => :updated_at

You must ensure that the versioned trigger always has a value, either through:

# using the dm-timestamps gem, which automatically updates the :updated_at attribute
timestamps :at

# or a callback method, that updates the value before save
before(:save) { self.updated_at = }

Without this, things just don't work.

Ensure you use dm-migrations gem

The post_versions table is NOT created unless you migrate your models through:

DataMapper.auto_migrate! / Post.auto_migrate!
DataMapper.auto_upgrade! / Post.auto_upgrade!

That’s about it.

Errors / Bugs

If something is not behaving intuitively, it is a bug, and should be reported. Report it here:


  • Make it work more like AR's :acts_as_versioned plugin, with support for multiple versions and so on.

  • Enable replacing a current version with an old version.

  • Anything else missing?

Note on Patches/Pull Requests

  • Fork the project.

  • Make your feature addition or bug fix.

  • Add tests for it. This is important so we don't break it in a future version unintentionally.

  • Commit, do not mess with rakefile, version, or history.

    • (if you want to have your own version, that is fine but bump version in a commit by itself we can ignore when we pull)

  • Send us a pull request. Bonus points for topic branches.


Copyright © 2011 Timothy Bennett. Released under the MIT License.

See LICENSE for details.


Credit also goes to these contributors.