README.rdoc

vestal_versions for Rails 3

Finally, DRY ActiveRecord versioning!

acts_as_versioned
by technoweenie was a great
start, but it failed to keep up with ActiveRecord's introduction of
dirty objects in version 2.1. Additionally, each versioned model needs its
own versions table that duplicates most of the original table's
columns. The versions table is then populated with records that often
duplicate most of the original record's attributes. All in all, not
very DRY.

vestal_versions
requires only one versions table (polymorphically associated with its
parent models) and no changes whatsoever to existing tables. But it goes
one step DRYer by storing a serialized hash of only the
models' changes. Think modern version control systems. By traversing
the record of changes, the models can be reverted to any point in time.

And that's just what vestal_versions does. Not only can a
model be reverted to a previous version number but also to a date or time!

When a model is created (or updated the first time after being versioned),
an initial version record with a number of 1 is no longer created. These
aren't used during reversion and so they end up just being dead weight.
Feel free to scrap all your versions where number == 1 after the
upgrade if you'd like to free up some room in your database (but you
don't have to).

Models that have no version records in the database will return a
@user.version of 1. In the past, this would have returned
nil instead.

Version has moved to VestalVersions::Version to make way
for custom version classes.

Version#version did not survive the move to
VestalVersions::Version#version. That alias was dropped (too
confusing). Use VestalVersions::Version#number.

New to 1.0

There are a handful of exciting new additions in version 1.0 of
vestal_versions. A lot has changed in the code: much better
documentation, more modular organization of features, and a more exhaustive
test suite. But there are also a number of new features that are available
in this release of vestal_versions:

The ability to completely skip versioning within a new
skip_version block:

Also available, are merge_version and append_version
blocks. The merge_version block will compile the possibly multiple
versions that would result from the updates inside the block into one
summary version. The single resulting version is then tacked onto the
version history as usual. The append_version block works similarly
except that the resulting single version is combined with the most recent
version in the history and saved.

Version tagging. Any version can have a tag attached to it (must be unique
within the scope of the versioned parent) and that tag can be used for
reversion.

So if you're not big on version numbers, you could just tag your
versions and avoid the numbers altogether.

Resetting. This is basically a hard revert. The new reset_to!
instance method behaves just like the revert_to! method except
that after the reversion, it will also scrap all the versions that came
after that target version.

Storing which user is responsible for a revision. Rather than introduce a
lot of controller magic to guess what to store, you can simply update an
additional attribute on your versioned model: updated_by.

Instead of passing a simple string to the updated_by setter, you
can pass a model instance, such as an ActiveRecord user or administrator.
The association will be saved polymorphically alongside the version.

Global configuration. The new vestal_versions Rails generator also
writes an initializer with instructions on how to set application-wide
options for the versioned method.

Conditional version creation. The versioned method now accepts
:if and :unless options. Each expects a symbol
representing an instance method or a proc that will be evaluated to
determine whether or not to create a new version after an update. An array
containing any combination of symbols and procs can also be given.

Custom version classes. By passing a :class_name option to the
versioned method, you can specify your own ActiveRecord version
model. VestalVersions::Version is the default, but feel free to
stray from that. I recommend that your custom model inherit from
VestalVersions::Version, but that's up to you!

A versioned? convenience class method. If your user model is
versioned, User.versioned? will let you know.

Soft Deletes & Restoration. By setting :dependent to
:tracking destroys will be tracked. On destroy a new version will
be created storing the complete details of the object with a tag of
'deleted'. The object can later be restored using the
restore! method on the VestalVersions::Version record. The
attributes of the restored object will be set using the attribute writer
methods. After a restore! is performed the version record with the
'deleted' tag is removed from the history.