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 reload! TestedModel.first.update_attribute :callback_triggering_attr, nil TestedModel.first.update_attribute :callback_triggering_attr, 'a real value' end
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.
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 table_name.id desc limit 1.
A quick check of the Rails docs revealed that the behavior of
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.