Betsy Haibel has an Online Presence

Recently, at the office, something happened that baffled me. I was doing some third-party integration testing from the rails console, which required multiple test runs of this approximate form:

    def test_run
      TestedModel.first.update_attribute :callback_triggering_attr, nil
      TestedModel.first.update_attribute :callback_triggering_attr, 'a real value'

After a test run succeeded in having the third-party effect I wanted, I checked to see if the callback had also triggered the subsequent resource updates I wanted:




Several very confused pry-debugger sessions later, I noted that the ids returned by my self call in the middle of prying and the id returned by TestedModel.first … did not match.

It turns out that ActiveRecord::Base.first is nondetermininistic. It generates SQL that looks something like select * from table_name limit 1, and the order of selects when no specific order clause is included is nondeterministic in the official SQL specification. It’s easy to forget that. The default order is typically creation order and creation order typically tracks ascending order by id in a Rails application. However, because computers are computers, it’s important to remember that typically != always.

Amusingly, ActiveRecord::Base.last<% end %> is deterministic. In order to retrieve the “last” record while still imposing a limit of 1 record retrieved, a descending order on some attribute must be imposed, like so: select * from table_name order by desc limit 1.

A quick check of the Rails docs revealed that the behavior of ActiveRecord::Base.first has been changed/corrected in Rails 4 so that a specific order clause on the primary key is included. I look forward to its behavior confusing fewer people in the future.