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
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.
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 |
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.
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.
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.
If something is not behaving intuitively, it is a bug, and should be reported. Report it here: datamapper.lighthouseapp.com/
-
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?
-
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.