ActiveRecord's update_column

Using update_column is usually a mistake

2016-08-17

#update_column used to be a critical performance tool before Rails had dirty attribute tracking. Now that ActiveRecord manages dirty tracking for us, there are very few legitimate uses of this function with a lot of serious down-sides.

When you use update_column to change a model, here’s what you get:

  • Validation is skipped
  • Callbacks are skipped
  • updated_at/updated_on and ‘lock_version’ are not updated

In the general case, these two calls to exactly the same thing:

1
2
@record.foo = 'bar'
@record.save(validate: false, touch: false)
1
@record.update_column(:foo, 'bar')

What you might save in line count you lose in clarity. You also expose yourself to unnecessary risks. The second option is much easier for a less experienced engineer to mis-read and to use inefficiently (by, for example, making two update_column calls in the same function). Choosing to skip validation and callbacks should always be explicit so it is not overlooked and so that the author has an opportunity to add a comment explaining why they need a special exception to their own safeguards.

Often when I see extensive use of update_column in a Rails app, it’s being used to store one of multiple text fields an a module, presumable to avoid the saving/loading of all the record’s text field. Unfortunately, it’s not actually providing much if any value in these cases, and it definitely doesn’t save the application from poor data design. A Next Level Developer avoids unnecessary optimizations, preferring to write predictable, clean, and transparent code.


NOTE: ActiveRecord has another method, update_attribute, which is equally to be avoided. This version skips validation, just like update_column, but does not skip callbacks and does update automatic columns like lock_version. Basically, it’s the worst of both worlds.