Surprise in Arel's API
arel
– A relational algebra library – is the ruby library that that powers ActiveRecord
. It provides a lower-level abstraction for working with SQL
than ActiveRecord
, and typically used when a particular query is not possible with ActiveRecord
. Over the years, I’ve reached out for it on occasion. The definitive guide to Arel, the SQL manager for Ruby provides good information if you haven’t used it before.
I was recently working with a complicated query, and spent way more time because I assumed some things about it’s API that turned out to not be true.
Let’s first observe how ActiveRecord::Relations
behave:
ar_relation = User.where.not(active_thru: nil)
ar_relation.to_sql
# => SELECT "users".* FROM "users" WHERE "users"."active_thru" IS NOT NULL
ar_relation.where(id: 5).to_sql
# => SELECT "users".* FROM "users" WHERE "users"."active_thru" IS NOT NULL AND "users"."id" = 5
ar_relation.to_sql
# SELECT "users".* FROM "users" WHERE "users"."active_thru" IS NOT NULL
Notice how calling a second where
on a relation returns a new relations without modifying the original. This allows composing relations in Rails with great effect.
However, that is not true with Arel::SelectManager
classes:
table = User.arel_table
arel_manager = table.where(table[:active_thru].not_eq(nil))
arel_manager.to_sql
# => SELECT FROM "users" WHERE "users"."active_thru" IS NOT NULL
arel_manager.where(table[:id].eq(5)).to_sql
# => SELECT FROM "users" WHERE "users"."active_thru" IS NOT NULL AND "users"."id" = 5
arel_manager.to_sql
# => SELECT FROM "users" WHERE "users"."active_thru" IS NOT NULL AND "users"."id" = 5
Notice how adding a new where
clause modified the original object.
Caveat Emptor
Find me on Mastodon at @ylansegal@mastodon.sdf.org,
or by email at ylan@{this top domain}
.