After years of working on OccamsRecord and wondering if and how any of it could be ported to Rails/ActiveRecord, I finally made the first step: Uberloader.
Uberloader is an “extension” (read: shameful monkeypatch) to ActiveRecord enabling you to customize the SQL of preloaded associations. Add a WHERE
condition, ORDER BY
, etc.
Example
widgets = Widget
.where(category_id: category_ids)
.uberload(:category)
# order parts
.uberload(:parts, scope: Part.order(:name)) do |u|
# Nested uberloads use blocks
u.uberload(:manufacturer)
u.uberload(:subparts) do
# do something to subparts's scope
u.scope my_subparts_scope_helper
u.scope Subpart.active if params[:only_active]
u.uberload(:foo) do
u.uberload(:bar)
end
end
end
Why not in the model?
You can easily customize the scope of an association when you define it in the model:
class Widget < ApplicationRecord
has_many :parts, -> { order(:name) }
end
But that’s not very flexible. What if one page/API wants them in descending order? Ordered by price? Filtered by status? You’re out of luck.
ActiveRecord::Associations::Preloader?
This does work. In fact it’s how Uberloader is implemented. But it’s a private, undocumented class. It’s not stable across major Rails versions, and it’s incredibly akward to use on nested associations. Uberloader papers over all those issues, but it is a monkeypatch.
Is this monkeypatched thing safe to use?
Probably. If no uberload
calls are made on a query, the patch simply calls super
. So non-uberloaded queries are quite safe. But what about queries that do use uberload
?
Uberloader has a version matrix test suite that tests every version of Uberloader, plus the latest git commit, against every (supported) version of ActiveRecord. It runs daily and records the results on GitHub. So unless you’re updating Rails versions same-day, you’re pretty well covered.
Why isn’t this in Rails?
I’d love to see it (likely with a different name). Maybe it will be my next project…