Save Ukraine

Rails: update dataset without updating magic timestamp columns

Christian Kruse,

In Rails, you can have several „magic columns” identified by their names. These columns include updated_at and 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 save

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:

def wo_timestamp(&block)
old = ActiveRecord::Base.record_timestamps
ActiveRecord::Base.record_timestamps = false
begin
yield
ensure
ActiveRecord::Base.record_timestamps = old
end
end

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.

Using update_all or update_column

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 save_wo_timestamp
class <<self
def record_timestamps; false; end
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 :-)