Bitten by HABTM Again
Posted on July 23rd, 2009 in rails | No Comments »
I while back needed to add an audit trail to an older project. I found the acts as audited plugin and put it into play and it is great. I added my models to it and added a way to review the audit trail online – all good – until…
I started added audits for my model associations. This went well until I wanted to audit a has and belongs to many (HABTM) association which as you know, doesn’t have to have a backing model (it simply relies on a join table that is named a particular way). Sigh. On a few HABTM as sociations, I actually had a model but our smarted myself (and followed an older web recipe) and created the model without id’s. These associations do not work with this plugin.
No way to get there from here exept to convert HABTM to has many through. Further evidence why HABTM is shortcut that only leads to pain later if you need to extend the associations (like adding audit trails).
Avoid HABTM and your life will be better…. just imagine having to convert 10 or more association tables to models on a production system that has 1000’s of parent objects. You see any fun in that? The superstitious would call how HABTM handles join objects as ‘magic’ which isn’t really very accurate. It is simply a conventional shortcut. My big problem with it is the lack of flexibility it gives you – it is one of those box-canyon paradigms that is hard to get out of.
Oh and another note, if you add acts_as_audited to your project late in the game, you may run into problems with migrations if any migrations load data. The reason is a fresh checkout will bring the audit code which will perform audits even on migrated data and since early migrations don’t have the audit table loaded yet (it is a later migration), you can’t migrate data. Sure you can just do a rake db:schema:load but that will leave you without some of your migration data.
An easy solution is to simply rename the acts as audited migration to be your first migration (mung the date in the file name). This tricks the migration to run first and all should be fine… Note, this even works if you have previously migrated and then do an update to get this new ‘old’ migration – the migration still runs even though it is out of sequence thanks to the schema_migrations table which keeps up with what migrations have been run.