Yes there is Table.update_counters(record.id, :my_counter => by_count) . But that’s not conditional – for example I want to update counter only if result will be >= 0. Atomically.
You can try something like
Table.update_counters(record.id, my_counter: -10) if record.my_counter >= 10
but it’s not really atomic operation (unless you wrap in transaction with row lock, which I don’t like).
And if you try this
Table.where('my_counter >= ?', 10).update_counters(record.id, my_counter: -10)
you will find it doesn’t really care about the where condition and it ignore it.
So what can I do? Right, I’m not, surprisingly, limited to predefined Rails methods but I have whole Ruby and ActiveRecord to act as my slave, not master. Little instance method in my model definition will do the job:
updated = self.class
.where('my_counter >= ?', -by)
"my_counter = COALESCE(my_counter, 0) + (%s)" %
return self unless updated > 0
Let me know what would you improve in comments