#177
Aug 31, 2009

Model Versioning

If you need to keep track of a model's history of changes and switch between versions, consider using the vestal_versions gem like I show in this episode.
Download (14.4 MB, 9:28)
alternative download for iPod & Apple TV (10.4 MB, 9:28)

Resources

sudo rake gems:install
script/generate vestal_versions_migration
script/generate migration version_existing_pages
rake db:migrate
# config/environment.rb
config.gem 'laserlemon-vestal_versions', :lib => 'vestal_versions', :source => 'http://gems.github.com'

# models/page.rb
class Page < ActiveRecord::Base
  versioned
end

# version_existing_pages migration
say_with_time "Setting initial version for pages" do
  Page.find_each(&:touch)
end

# pages_controller.rb
def show
  @page = Page.find(params[:id])
  @page.revert_to(params[:version].to_i) if params[:version]
end

# script/console
p = Page.all
p.versions
p.revert_to(7.minutes.ago)
p.content
p.revert_to(:last)
<p>
  <%= link_to "Edit", edit_page_path(@page) %>
  | Version <%= @page.version %>
  <% if @page.version > 1 %>
    | <%= link_to "Previous version", :version => @page.version-1 %>
  <% end %>
  <% if params[:version] %>
    | <%= link_to "Latest version", :version => nil %>
  <% end %>
</p>

RSS Feed for Episode Comments 32 comments

1. Torsten Aug 31, 2009 at 00:23

this is much nicer than acts_as_versioned! Thanks for pointing this out.


2. Aditya Sanghi Aug 31, 2009 at 01:25

Hi Ryan,
Minor typo in your blog post, it's vestal_versions i believe, not vistal_versions.

Cheers,
Aditya


3. August Lilleaas Aug 31, 2009 at 03:42

Out of curiosity, where's the wiki_link helper in your show.html.erb form?


4. Tobias Aug 31, 2009 at 06:21

Thanks a lot thats just what I was locking for for our next sprint next week :-).


5. Shane Aug 31, 2009 at 06:55

Might I also suggest taking a look at has_versioning:

http://github.com/kkurach/has_versioning/tree/master

It doesn't only version models, it will also version associations (though not yet via has_many through) and allows for rollback.

You can even lump a whole bunch of changes into a single changelist so that you can later undo them all at once later if need be...


6. Ryan Bates Aug 31, 2009 at 07:25

@Aditya, fixed, thanks!

@August, the wiki_link helper method is inside the application_helper.rb file. Check out the full source code link in the show notes.

@Shane, thanks for pointing this out! I hadn't heard of has_versioning.


7. Jon Aug 31, 2009 at 07:43

I'm wondering how to get this to work with associated models, so if the associations change this is reflected in the versioned model.

I could implement a simple after_update method that touches the parent (i.e. versioned) model when the associated model is updated but I'm wondering will the parent model recognise the changes. Particularly as the main aspect that will change on the associated model is the attached file via paperclip!


8. Brian Armstrong Aug 31, 2009 at 07:47

If anyone wants to do a "diff" output with this to compare versions, check out HTMLDIff
http://github.com/myobie/htmldiff/tree/master

It will put new stuff in green, old in red with strikethrough, etc.

I setup something like this with the acts_as_audited plugin a while back which is also good, looks very similar.


9. Andy Stewart Aug 31, 2009 at 09:15

This looks good.

You may also like my PaperTrail gem, which doesn't require you to touch existing records to store their starting state. It also lets you recover destroyed records, and copes with intermediate schema changes. It also records who was responsible.


10. Andy Stewart Aug 31, 2009 at 09:15

Forgot the link:

http://github.com/airblade/paper_trail/tree/master


11. Karol Aug 31, 2009 at 09:56

@Shane
has_versioning plugin ( http://github.com/kkurach/has_versioning/tree/master ) doesn't support rollbacks yet. everything else you wrote is correct :)

it supports tracking objects AND associations, and also packing many changes into one changelist


12. Michael Schuerig Aug 31, 2009 at 13:34

Anyone wondering about the name of the vestal_versions plugin probably needs to listen to A Whiter Shade of Pale

http://www.youtube.com/watch?v=PbWULu5_nXI


13. Chris Gunther Aug 31, 2009 at 19:42

Great screencast on a useful gem. Now I have to find a project to use it in.


14. sthapit Sep 01, 2009 at 04:49

works great but one problem - my model has a "state" column that gets changed from "pending" to "active". this would allow users to revert an active post to pending - is there a way to prevent Vestal Versions from not tracking a specific column (in this case the "state" column)? thanks!


15. sam Sep 01, 2009 at 07:17

Hi, very nice screencast

can someone explain me what the & in

Page.find_each(&:touche)

does?

thx


16. hartwig Sep 01, 2009 at 16:06

@sam
Event shorter: Ryan made an episode about that: http://railscasts.com/episodes/6-shortcut-blocks-with-symbol-to-proc

In short: its just a shortcut for
Page.find_each{|item| item.touche}

The & converts the symbol to a proc object ( to be more specific the & calls the to_proc method on the symbol or on any other object), which gets then called for each object which find_each returns.

Thats feature is in ruby 1.9 per default, or you can define it like rails did.

Look at http://blog.hasmanythrough.com/2006/3/7/symbol-to-proc-shorthand and search for to_proc
 


17. Aaron Sep 01, 2009 at 19:54

I've been using acts_as_revisable on my project, which has worked out extremely well, it seems to be a bit more developed, and works very will in conjunction with AASM. acts_as_revisable also supports association versioning as detailed in the without_scope blog: http://withoutscope.com/2009/5/12/simple-association-versioning-with-acts_as_revisable

http://github.com/rich/acts_as_revisable/tree/master


18. Robert Sep 01, 2009 at 23:50

What version of Rails does vestal_versions require, will it work on 2.1?


19. vidar Sep 02, 2009 at 03:36

For getting the log and the hirb working, install the hirb gem and put

if ENV['RAILS_ENV']
  require 'rubygems'
  require 'hirb'
  require 'activerecord'
  Hirb.enable
  ActiveRecord::Base.logger = Logger.new(STDOUT)
end

into .irbrc and then fire up script/console


20. Vishnu Shashank Sep 03, 2009 at 04:27

I was using acts_as_versioned. Thanks Ryan. This one is good.
@Bryan, Thanks. I got the HTMLDiff working as well. Its fantastic.


21. Matias Korhonen Sep 05, 2009 at 05:37

Maybe it's about time for a Railscast on anti-spam measures?


22. Dji Sep 07, 2009 at 18:04

It might be time for a Railscast on implementing Captcha and eliminating spam.


23. mikhailov Sep 10, 2009 at 07:33

It's pretty cool!
By the way, isn't hard implementation


24. Everlast Sep 12, 2009 at 03:12

Hi,
I've been using acts_as_versioned with acts_as_paranoid, which need(ed) a custom patch to work proprely together in a project (the patch ensured that deleting a record not only sets the deleted_at column to the current date-time, but also moves it to the *_versions table and was provided on the versioned act track or somewhere like that; btw the patch on the site didn't work but I mailed the author and he gave me the correct one - obviuosly he didn't upload the patch right but was very helpful).
Since Rails 2.1.x came out with the enhanced change-tracking functionalities and acts_as_versioned stopped working, I'm stuck using Rails 2.0.2 for that project.
So, my question is: Is there a way/act/plugin to achieve what I now have with newer Rails versions?
The idea is that I need to keep track of both changes and deletions


25. sthapit Sep 24, 2009 at 02:11

I ended up creating a simple fork of vestal_versions so that I could specify which columns to include or exclude. Details are at http://github.com/sthapit/vestal_versions


26. kb Oct 08, 2009 at 06:00

In Rails 2.3.4 it says: undefined method `password_confirmation' for #<User:0x7f4ffda0a7e0>

I added an
  attr_accessor :password_confirmation

to the User-Model

But still got the Error:
Password confirmation is too short (minimum is 4 characters)


27. gs boat Dec 18, 2009 at 00:44

right


28. yeni müzik Dec 29, 2009 at 15:51

very useful screencast. thanks.


29. wholesale nike shoes Jan 13, 2010 at 23:17

A very good article, I will always come in.


30. fashion scarves Jan 13, 2010 at 23:17

Such a good article, caught my sympathy!
-


31. javon Jan 25, 2010 at 22:33

article, caught my sympathy


32. diyugg Feb 03, 2010 at 19:39

I recently came across your blog and have been reading along. I thought I would leave my first comment. I don’t know what to say except that I have enjoyed reading.

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(use pastie or gist for code)

sponsored by:
if you want to help:
required:
Get Quicktime Player
Give Back to Open Source