2007-03-01 @ 11:02

Audit Logs with ActiveRecord

I’ve been trying to create an audit log for a few (12) tables, and unfortunately ActiveRecord seems to be falling flat for what I want to do. First I’ll describe whats out there already to do this, then I’ll talk about what I had to do.

There are a couple nice plugins out there for helping you keep track of changes to your records. The first one is acts_as_versioned. acts_as_versioned will copy your record to a version table whenever there is an insert or update, then increase a version number in the original table. It also automatically adds a list of versions to your original model, and lets you revert to any particular version. This is great, and almost exactly what I needed. I didn’t really need the ability to revert to a version, but that just seemed like gravy on top. The only problem with acts_as_versioned comes in when you try to keep track of changes to habtm relationships. But this is where the second plugin comes in to play.

The second plugin is called acts_as_versioned_association. This plugin will help you keep track of changes to your relationships. acts_as_versioned_association is built on top of acts_as_versioned. They way it works is by setting the owner model to acts_as_versioned, then when any associations are updated, it writes a new version of the owner model, then writes the associations to a associations version table. So if you were to have an Article model that has and belongs to many Documents, you would need 5 tables to represent that:

  1. articles
  2. articles_versions
  3. documents
  4. articles_documents
  5. articles_documents_versions

If the association changes, a record is written to articles (to increase the version number), articles_versions, articles_documents, and articles_documents_versions. But what happens if Article has 10 versioned habtm relationships, and just one of those relationships changes? Then a record will get written to every habtm version table for just one change. Thats 12 writes for a change to just one relationship. That will not scale….

Fortunately I don’t care about reverting to a previous version. All I care about is what changed, and when. So my favorite solution for this problem is to add triggers to the tables that may change. That way I only get one extra write when a relationship changes. Just copy the row to another table with a timestamp and an action.

But what about has_many :through?

has_many :through allows you to put a model on top of the join table. Then I could just drop acts_as_versioned on top of that model and be done. I would have used this solution except that I ran in to a bug. has_many :through does not support all of the same array manipulation that habtm does. For example, you can append («) to has_many :through and habtm, but the clear method does not work the same way on has_many :through. Also, has_many :through does not set an attribute= method like habtm does.

read more »

2007-03-01 @ 14:32

Trigger Happy

I’ve just released “Trigger Happy”, a rails plugin that adds support for triggers in your Active Record Migrations. To install the plugin just do this:

script/plugin install svn://rubyforge.org/var/svn/artriggers/trunk/trigger_happy ~~~

To add a trigger do this:

add_trigger "ai_people",
  :on         => 'people',
  :timing     => 'after',
  :event      => 'insert',
  :statement  => 'INSERT INTO log (id, timestamp) VALUES (NEW.id, NOW())'

To drop a trigger do this:

drop_trigger "ai_people"

It only supports mysql for now, but I plan on having other database supported in the future.

read more »

2007-03-05 @ 15:44

Heat of the Moment

I like news anchor catch phrases and play on words. Things like “Bob was just an ordinary man, but was forced to do something extraordinary”, or “Bill was buying a dirty magazine one day when he got more than he bargained for”. I try to do the same thing when I’m talking to people at work about programming but people seem to get annoyed with me. I’ll say things like “I decided to use a linked list and ended up with more that I had bargained for”. I also like mixing in rap lyrics, so I’ll be like “you down with MVC? Ya you know me!”

Speaking of rap lyrics, something awesome happened to me the other day. Someone sent me $50 for my work on ruby mechanize. I’ve never had someone donate to me for work I’ve done, and I’m very grateful! I say who did it because I haven’t asked if I could, but I want to say thanks!

I helped Katie move this weekend, and now I’ve got Geography rock songs stuck in my head. Here’s my Geography rock playlist so far:

  1. Asia – Heat of the Moment
  2. Europe – The Final Countdown
  3. Boston – Peace of Mind
  4. Kansas – Carry on My Wayward Son
  5. Chicago – Does Anybody Really Know What Time it is?
  6. America – Ventura Highway

I can’t decided if I should keep the list classic rock because I could have a lot more options like Sleater-Kinney, Of Montreal, and more. Also, if you might be able to include Journey because I journey through life on a highway. Or something. I want to add an America song to the list, but I can't think of a good one. I don’t really like that “Horse with no Name” song, but that “Ventura Highway” song is okay. Also does “Starland Vocal Band” count? Does anyone else have some good picks?

I really didn’t like geography when I was a kid and I wish I had been in to these bands because it may have encouraged me to like geography more.

In conclusion, I would like to say hello to my readers from India! I’ve noticed that 8% of my traffic is from India, so thanks for reading!

read more »

2007-03-15 @ 18:11

mechanize version 0.6.5 has been released!

The Mechanize library is used for automating interaction with websites. Mechanize automatically stores and sends cookies, follows redirects, can follow links, and submit forms. Form fields can be populated and submitted. Mechanize also keeps track of the sites that you have visited as a history.


= Mechanize CHANGELOG

== 0.6.5

  • Copying headers to a hash to prevent memory leaks
  • Speeding up page parsing
  • Aliased fields to elements
  • Adding If-Modified-Since header
  • Added delete_field! to form. Thanks to Sava Chankov
  • Updated uri escaping to support high order characters. Thanks to Henrik Nyh.
  • Better handling relative URIs. Thanks to Henrik Nyh
  • Now handles pipes in URLs http://rubyforge.org/tracker/?func=detail&aid=7140&group_id=1453&atid=5709
  • Now escaping html entities in form fields. http://rubyforge.org/tracker/?func=detail&aid=7563&group_id=1453&atid=5709
  • Added MSIE 7.0 user agent string
read more »

2007-03-16 @ 17:18

What's in a name?

I’m trying to come up with a name for a ruby library I’m writing. Basically this library will convert javascript in to ruby. Here’s the list of options I have so far:

  1. rkelly
  2. rtaco
  3. burrito
  4. rawr

So far the front runner is ‘rkelly’. Does anyone have any suggestions? Or particularly like any of those names?

Update: I changed “taco” to “rtaco” so that all of the names have “r” in them. “r” for Ruby, “taco” for Taco! Update 2: Added “rawr”!

read more »

2007-03-29 @ 17:07

mechanize version 0.6.7 has been released!

The Mechanize library is used for automating interaction with websites. Mechanize automatically stores and sends cookies, follows redirects, can follow links, and submit forms. Form fields can be populated and submitted. Mechanize also keeps track of the sites that you have visited as a history.


= Mechanize CHANGELOG

== 0.6.7

  • Fixed a bug with keep-alive requests
  • [#9549] fixed problem with cookie paths
read more »