This looks harmless:
if order.line_items.present?
# ...
end
It reads like a pure boolean check. In ActiveRecord associations, it sometimes isn't.
Under the hood, present? delegates to blank?, which for un-loaded associations cascades down to empty?. When empty? is called, ActiveRecord may hit the database to determine if records exist. The method name suggests a local predicate. The behavior sometimes crosses the database boundary.
Without preloading, this simple check can become surprisingly expensive in aggregate:
orders.each do |order|
next unless order.line_items.present?
# ...
end
In a loop, it becomes one query per order. It scales with record count. It doesnโt look like I/O at the call site.
In long-lived systems, I try to make database boundaries obvious in code. If a predicate can hit the database, I want that to be visible. Using exists? makes the I/O explicit. Alternatively, preloading the association upfront ensures that present? remains a purely in-memory check. Being explicit about these access patterns removes ambiguity.
Convenience helpers are useful. But when they conceal I/O, they also conceal cost. In small systems, that rarely matters. In mature ones, it adds up.
This pattern appears frequently when diagnosing performance in long-lived Rails systems.
Top comments (0)