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:

<pre class=”brush: ruby”>def wo_timestamp(&amp;block) old = ActiveRecord::Base.record_timestamps ActiveRecord::Base.record_timestamps = false begin yield ensure ActiveRecord::Base.record_timestamps = old endend</pre></code><p> 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.</p><h3>Using <code>update_all</code> or <code>update_column</code></h3><p> Nice solution, threadsafe and no magic. Both fire an <code>UPDATE</code> statement w/o setting the timestamp values. Nice, but needs more complicated and less readable code. With <code>update_column</code> you also need to call it once for every column.</p><h3>Use meta programming</h3><p> Rails uses a callback method <code>record_timestamps</code> to decide if it should update the timestamp columns. This gives us the ability to do this on just one object:</p><code><pre class=”brush: ruby”>def save_wo_timestamp class &lt;&lt;self def record_timestamps; false; end end begin self.save ensure class &lt;&lt;self remove_method :record_timestamps end endend</pre></code><p> I overwrite the method on this specific object, save it to database and remove the overwritten method after that. Nice, clean and easy. Yay :-)</p>