Rails: update dataset without updating magic timestamp columns
In Rails, you can have several „magic columns” identified by their names. These columns include
created_at. The latter one is set to the current time when a dataset is created and the first one is set to the current time when a dataset gets updated.
For a work project I had to update some values (a lock field for example) w/o updating these magic columns. After doing some research on the interwebs there are several solutions:
Disabling magic columns before calling
This was the first and easiest one. You can simply set
ActiveRecord::Base.record_timestamps = false and then call
save. Wrapped up in a helper method this would be like this:
old = ActiveRecord::Base.record_timestamps
ActiveRecord::Base.record_timestamps = false
ActiveRecord::Base.record_timestamps = old
This is fine because it is easy, but it's not threadsafe. In my case I needed a threadsafe solution because it was a threaded server application.
Nice solution, threadsafe and no magic. Both fire an
UPDATE statement w/o setting the timestamp values. Nice, but needs more complicated and less readable code. With
update_column you also need to call it once for every column.
Use meta programming
Rails uses a callback method
record_timestamps to decide if it should update the timestamp columns. This gives us the ability to do this on just one object:
def record_timestamps; false; end
begin self.save ensure class <<self remove_method :record_timestamps end end end
I overwrite the method on this specific object, save it to database and remove the overwritten method after that. Nice, clean and easy. Yay :-)