Revisioning with acts_as_audited
When I first created acts_as_audited over a year ago, I intended to add versioning/revisioning capabilities, but found I never really had a need. Well, it just so happened that I finally had a need on an app that we are working on. So, acts_as_audited now allows you to revert back to previous revisions.
You can get all the revisions of a model:
article.revisions.each |revision|
puts revision.class #=> Article
puts revision.version #=> 7, 6, 5, 4...
end
or a specific revision:
revision = article.revision(5)
puts revision.title #=> "Old Title"
or the previous revision. Reverting is as simple as saving a revision:
previous = article.revision(:previous)
previous.save # revert to previous revision
See the original post for more details about installing and using the plugin.
How is this different from acts_as_versioned?
I’ve never used acts_as_versioned1 (because I’ve never had a need to do versioning), but I do know that it has a few annoying limitations: 1) it requires a separate table (and model) for each model that you want to version, and 2) it saves every attribute, even if it’s not changed.
acts_as_audited already stories all the changes (and only the changes) in one table, so adding versioning was rather trivial. Revisions are created by walking backward through the audits, collecting the changes, and returning an instance of the model.
Upgrading
To use the versioning support, you must add a version field in the audits table:
add_column :audits, :version, :integer, :default => 0
Note: if you already have audit records, the version field will have to be initialized.
Feedback
This code is fairly specific to what I needed, so if you’re using it, I would love to hear how it is working for you. Suggestions and patches welcome.
- acts_as_audited was actually one of the first plugins that I wrote, so I looked at the best code I could find as an example for writing a plugin, which happened to be acts_as_versioned. Kudos to technoweenie.








19 comments
That’s funny.. I just looked over your old blog post and thought I could use this… :-) Thanks for your work.
June 18, 2007 at 03:47 PM
w00t! Thanks very much. I commented on the original blog post about adding this feature. I will test it out as soon as I get a chance.
June 18, 2007 at 05:47 PM
Sigh, just an update. I got bogged down in my project (wife is pregnant, I have a good excuse) and wasn’t able to test the revisioning yet. But hopefully someone has… :)
July 26, 2007 at 02:04 AM
Hello, I’m trying to use acts_as_audited with ActiveScaffold (http://activescaffold.com) but for some reason, it pukes in the “after” filter in the caching.
If I comment out line 602 in vendor/rails/actionpack/lib/action_controller/filters.rb it works great, but I’m guessing this is bad since cached objects won’t be invalidated or something…
Any suggestions?
July 30, 2007 at 06:28 PM
Here’s the relevant exception:
NoMethodError (You have a nil object when you didn’t expect it! The error occurred while evaluating nil.controller_name): /vendor/rails/actionpack/lib/action_controller/caching.rb:602:in `callback’ /vendor/rails/actionpack/lib/action_controller/caching.rb:595:in `after’ /vendor/rails/actionpack/lib/action_controller/filters.rb:602:in `proxy_before_and_after_filter’
July 30, 2007 at 06:30 PM
Hey this is cool! =)
August 09, 2007 at 07:56 PM
Would be nice if you could retrieve a revision by date as well, since the audit table holds a created_at.
August 23, 2007 at 02:11 PM
Would also love this to co-operate better with Globalize model translations.
August 23, 2007 at 02:43 PM
A great plugin. Unfortunately it seems to have suffered on Edge rails as a result of the decision to make acts_as_list a plugin… even after installing the acts_as_list plugin one has to comment out line 14 of audit.rb in order to get the server to start…
Is there an easy fix? Thanks.
September 18, 2007 at 10:49 AM
I am trying to test the moves from one revision to the other in my functional tests and it seems like the models are not keeping all the changes, what am I supposed to do to make the test works?
October 07, 2007 at 06:05 PM
This is a great addition to my rails/ruby arsenal! I was wondering if anyone has developed a controller and view to display all of the revisions and possibly revert back to one?
October 10, 2007 at 04:37 PM
Ryan,
I’ll try to clean up the one that I have and post it. Stay tuned.
October 12, 2007 at 09:57 AM
Hi Brandon,
Thanks for the plugin. It is exactly what I was looking for.
I was looking for information of maintaining an audit trail for a project I am working on and I stumbled upon your previous blog post.
Regards Surat
October 15, 2007 at 04:32 PM
Is there a way to only revert certain attributes? If we have updated first and last name, can I accept the changed last name but not first name?
December 06, 2007 at 01:05 PM
Ryan,
Not really. You could retrieve a revision and just manually set the attributes. If you’d like to submit a patch, I’d be happy to accept it.
December 06, 2007 at 10:07 PM
Hi Brandon,
Great plugin, thanks.
I just wonder how could I get the updated date/time of each revision?
e.g. i would like to show a revision history, then i have:
for rev in @article.revisions puts rev.version puts rev.updated_at end
but then updated_at always show the last revision’s timestamp.
December 21, 2007 at 06:13 AM
I vote to add Peter’s diff, which further enhances acts_as_audited to save a record’s attributes when it is deleted, and gives you an easy way to restore it, with the original id (e.g., Client.revive(2344)).
January 31, 2008 at 03:41 PM
I’m getting the following error when calling the
method on an audited object.NoMethodError: undefined method `first' for Sun Jun 29 17:54:32 +0200 2008:Time from /home/daniel/Projects/mango/vendor/plugins/acts_as_audited/lib/acts_as_audited.rb:149:in `changes' from (irb):5:in `inject' from /home/daniel/Projects/mango/vendor/plugins/acts_as_audited/lib/acts_as_audited.rb:148:in `each' from /home/daniel/Projects/mango/vendor/plugins/acts_as_audited/lib/acts_as_audited.rb:148:in `inject' from /home/daniel/Projects/mango/vendor/plugins/acts_as_audited/lib/acts_as_audited.rb:148:in `changes' from /home/daniel/Projects/mango/vendor/plugins/acts_as_audited/lib/acts_as_audited.rb:147:in `collect' from /home/daniel/Projects/mango/vendor/plugins/acts_as_audited/lib/acts_as_audited.rb:147:in `changes' from /home/daniel/Projects/mango/vendor/plugins/acts_as_audited/lib/acts_as_audited.rb:133:in `revision' from (irb):5Am I the only one with this problem?
June 29, 2008 at 12:07 PM
I’m surprised that acts_as_audited was your plugin. It’ll probably make a guest appearance here at Bluefish.
July 15, 2008 at 08:01 PM
Speak your mind: