CrudVision - Lisa Seelye

July 2, 2007

I did something evil today

Filed under: rails, work — Lisa Seelye @ 21:07

I did something quite evil today at work.

A customer wants to be able to roll back changes made by its moderators. If there's a difference of opinion they want to roll back a change. Makes sense. (No, it isn't a wiki.)

I decided that a second-best effort (instead of doing:

RUBY:
  1. AdminEditLog.create(:user => @session_user, :description => "Set object=#{@object.inspect}")

I'd do:

RUBY:
  1. old = Marshal.dump(@object)
  2. @object.update_attributes(params[:object])
  3. AdminEditLog.create(:user => @session_user, :old => old, :current => Marshal.dump(@object.reload))

Why is it evil? It requires two BLOB fields in MySQL, stores the ENTIRE object, twice and can't be searched upon.

The next iteration will likely just be a diff. Something like:

RUBY:
  1. def object_diff(o,c)
  2. changes = {}
  3. c.attributes.each do |k,v|
  4. if o[k] != v
  5. changes[k.to_sym] = v
  6. end
  7. end
  8. changes
  9. end
  10. Marshal.dump(object_diff(old_obj,new_obj)) # Store this, works for the arbitrary models

It is just a little better. They want to revert back to it so there's no need to do the diff after, upon reverting.

It works and I was impressed how easy it was because the revert action is simply to Marshal.load the old object and to just .save it.

Ruby is love. Just don't abuse it by stuffing crap into the database!

2 Comments »

  1. Eviiiiil! :)

    A different approach would be using acts_as_versioned to keep trac of changes using
    version.

    No marshal-dump-thing needed lol

    Comment by Rodrigo Kochenburger — July 5, 2007 @ 00:58

  2. acts_as_versioned, from what I understand of the plugin, isn’t what we wanted. The client wanted to only have a revision history of a certain subset of users and not the general userbase.

    Comment by Lisa Seelye — July 5, 2007 @ 22:34

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress