Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
DataMapper plugin enabling simple versioning of models
Ruby

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
lib
spec
tasks
.gitignore
Gemfile
LICENSE
README.rdoc
Rakefile
VERSION
dm-is-versioned.gemspec

README.rdoc

dm-is-versioned

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.

Installation

Stable

Install the dm-is-versioned gem.

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

Edge

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

end

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.

Usage

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"
post.save

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

This is how it would look like:

# db.post 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   |

#versions

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.

Gotchas

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
  <snip...>
  property :updated_at, DateTime

  is_versioned :on => :updated_at
end

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 = Time.now }

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: datamapper.lighthouseapp.com/

TODOs

  • 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

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

See LICENSE for details.

Credits

Credit also goes to these contributors.

Something went wrong with that request. Please try again.