Skip to content

Instantly share code, notes, and snippets.

@lukeredpath
Created August 31, 2010 15:19
Show Gist options
  • Select an option

  • Save lukeredpath/559187 to your computer and use it in GitHub Desktop.

Select an option

Save lukeredpath/559187 to your computer and use it in GitHub Desktop.
class Foo
has_many :bars
end
class Bar
belongs_to :foo
belongs_to :qux
end
class Qux
# no inverse to bar
end
puts Foo.first(:include => {:bars => :qux}).bars
# Loads Foo (LIMIT 1)
# Loads Bars where foo_id = Foo.id
# Loads Quxes where ID in (Bars.map(&:qux_id))
# 3 queries, as expected
# BUT
puts Foo.first(:include => {:bars => :qux}).bars.map(&:qux)
# Loads Foo (LIMIT 1)
# Loads Bars where foo_id = Foo.id
# Loads Quxes where ID in (Bars.map(&:qux_id))
# Loads Qux where ID == x
# Loads Qux where Id == x+1
# ...
# For each Qux in Bars
# W. T. F.?
# this is the Rails 3.0 version, same behaviour as above, n+1 queries:
puts Foo.includes(:bars => :qux).first.bars.map(&:qux)
## UPDATE!
# The problem only happened where foo.bars.qux returned nil (i.e. bar had a qux_id references a Qux that
# no longer existed). Because Qux is nil, Rails tries to get it by querying the database. So its really
# a data integrity issue; if you expect Bars to always have a Qux, make sure your model reflects that
# with appropriate validation! The ActiveRecord behaviour in this case makes total sense.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment