ActiveRecord Attribute Delta Updates
August 05, 2009Typically, when you update an attribute and save it using ActiveRecord in highly concurrent applications, you either have to use locking or be okay with clobbering the attribute with the last written value. In some cases, the nature of the data requires that locking be used if you want to maintain accuracy. But in other cases, specifically with numerical attributes, you can use SQL to express the difference you wish to apply.
1 UPDATE `widgets` SET `number` = 5 WHERE `id` = 1; 2 -- vs 3 UPDATE `widgets` SET `number` = `number` + 5 WHERE `id` = 1;
So in the first case, if you have 3 clients who first load the model from the database, and then all change the number attribute and then save it, you get something like this:
1 UPDATE `widgets` SET `number` = 3 WHERE `id` = 1; 2 UPDATE `widgets` SET `number` = 9 WHERE `id` = 1; 3 UPDATE `widgets` SET `number` = 4 WHERE `id` = 1;
When in actuality, the first one wanted to go from 0 to 3, the second from 0 to 9, and the last 0 to 4. If the second and third clients had known about the previous updates, the end value would be 16, but instead it's 4 because the last update overrode the previous. In some cases, this is intended, but not in all.
A solution to this problem is to make ActiveRecord use the alternate syntax to set the difference from the current value. Here's a gem to do that for you: ar-deltas
1 class Widget < ActiveRecord::Base 2 delta_attributes :number_one, :number_two 3 end 4 5 model = Widget.find(1) 6 puts model.number #=> 0 7 model.number += 5 8 model.save 9 10 # Before: 11 # UPDATE `widgets` SET `number` = 5 WHERE `id` = 1; 12 13 # After: 14 # UPDATE `widgets` SET `number` = `number` + 5 WHERE `id` = 1;
Comments
Leave a Comment