jordanm
jordanm

Reputation: 34964

Eager loading sibling records without including self

For serialization I want to include an array of sibling records which shares a common foreign key. I currently have the following:

class Foo < ActiveRecord::Base
  has_many :other_instances,
           source: :foo,
           class_name: 'Foo',
           foreign_key: 'event_id',
           primary_key: 'event_id'

When used in an include, it produces the following queries:

  Foo Load (0.2ms)  SELECT  "foo".* FROM "foo" WHERE "foo"."id" = $1 LIMIT 1  [["id", 21138]]
  Foo Load (0.4ms)  SELECT "foo".* FROM "foo" WHERE "foo"."event_id" IN (11451)

This mostly works, but the issue is that Foo.other_instances includes itself. Is there any way to exclude that additional record in rails? The expected includes would look something like this:

  Foo Load (0.4ms)  SELECT "foo".* FROM "foo" WHERE "foo"."event_id" IN (11451) AND "foo"."id" NOT IN (21138)

Update:

Attempting to make the condition instance dependent as in @spikermann's results in the following:

Code:

has_many :other_instances,
         source: :foo,
         class_name: 'Foo',
         foreign_key: 'event_id',
         primary_key: 'event_id', 
         ->(foo) { where.not(id: foo.id) }

Called with:

Foo.includes(:other_instances).find(21138)

Result:

DEPRECATION WARNING: The association scope 'other_instances' is instance dependent (the scope block takes an argument). Preloading happens before the individual instances are created. This means that there is no instance being passed to the association scope. This will most likely result in broken or incorrect behavior. Joining, Preloading and eager loading of these associations is deprecated and will be removed in the future. (called from check_preloadable! at /home/jordan/prog/knotweed/vendor/bundle/gems/activerecord-4.2.7.1/lib/active_record/reflection.rb:362)
NoMethodError: undefined method `id' for nil:NilClass

Upvotes: 0

Views: 215

Answers (1)

spickermann
spickermann

Reputation: 106972

What about adding a scope:

has_many :other_instances,
         source: :foo,
         class_name: 'Foo',
         foreign_key: 'event_id',
         primary_key: 'event_id', 
         ->(foo) { where.not(id: foo.id) }

Upvotes: 1

Related Questions