Skip to content

Instantly share code, notes, and snippets.

@jaydorsey
Last active January 2, 2025 17:45
Show Gist options
  • Save jaydorsey/e0ce28057188e45cdf12ae8866ab5069 to your computer and use it in GitHub Desktop.
Save jaydorsey/e0ce28057188e45cdf12ae8866ab5069 to your computer and use it in GitHub Desktop.
ActiveRecord stuff
# frozen_string_literal: true
# Brief overview of ActiveRecord preload, eager_load, includes, and joins
# id
# email
class Foo < ApplicationRecord
has_one :bar
end
# id
# name
# foo_id
class Bar < ApplicationRecord
belongs_to :foo
end
# left join has all records from main clause, regardless of child/related records
# inner join has all records from main clause where child/related record also has a record
#
# nothing
#
Bar.where(<where clause>).map { |b| b.foo.email }
# N+1 query, b.foo calls a query each iteration
#
# preload
#
Foo.where(<where clause>).preload(:bar).map { |f| f.bar.name }
# preload does 2 queries, but skips the risk of an inefficient join
# you can't add a where clause on bar
#
# eager_load
#
Foo.where(<where clause>).eager_load(:bar).where(bars: { name: 'blah' }).map { |f| f.bar.name }
# eager_load forces a left join so it's 1 query (all Foo records, even if no related Bar)
#
# includes
#
Foo.includes(:bars).where('email like %blah%')
# uses preload, because we don't need to reference the related/child table
Foo.includes(:bars).references(:bars).where('bars.name like %blah%')
# uses eager_load to force a left join since we are querying against the related/child table
# have to use references to use the child/related table in the query
#
# joins
#
Foo.joins(:bars)
# 1 query, an inner join that includes all Foo records where we have at least 1 matching Bar
Foo.joins(:bars).where("name like '%blah%'")
# 1 query, you can query against the related
# end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment