PagerDuty Blog

More control over Optimistic Locking in Rails

Like pretty much everything else in Rails, optimistic locking is nice and easy to setup:  you simply add a “lock_version” column to your ActiveRecord model and you’re all set.  If a given Rails process is trying to update some record, and some other process sneakily manages to update that same record while the first process wasn’t looking (locking?!?), then the first process will get a ActiveRecord::StaleObjectError when trying to save it’s stale data to the DB.

Unfortunately, however, like pretty much all the other convenient magic in Rails, it can be hard to fine-tune the behavior according to your needs.  Say, for instance, that your row has a field containing statistics data (like a counter), or some other piece of data that (A) you don’t mind becoming a little stale, or (B) should occasionally be updated in the background and shouldn’t interfere with the saving of other (more important) updates.  In these cases, the built-in optimistic locking can get a bit annoying.

Yes, you could always break these fields out into a new table/model of its own, with a has_one relationship, but you might not want to jump through those hoops.  Fear not!  Using the below module, you can simply add the lines:

      include SelectivelyOptimisticallyLockable
      skip_optimistic_locking :field_name

to your ActiveRecord model, any updates to the field in question won’t increment your lock_version counter nor can it fail with StaleObjectErrors.  (Tested in Rails 2.3.X)