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
: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.