You can't actually define an assocation like that since the definition of an assocation is class and not instance level.
While you can use a lambda to add default scoping to an assocation that lambda does not take arguments as there is no way to pass those arguments when joining, including or eager loading an association. self
inside the lambda is an association proxy and not the record itself so you can't write ->{ where.not(id: self.id) }
.
What you can do is write an instance method:
class Person < ApplicationRecord
belongs_to :parent, optional: :true,
class_name: 'Person'
has_many :siblings, class_name: 'Person',
foreign_key: :parent_id,
primary_key: :parent_id
def siblings
# super is the getter created by the association
super.where.not(id: self.id)
end
end
Example usage:
irb(main):001:0> Person.all
Person Load (0.2ms) SELECT "people".* FROM "people" LIMIT ? [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Person id: 1, name: "Odin", parent_id: nil, created_at: "2021-01-05 20:36:23", updated_at: "2021-01-05 20:36:23">, #<Person id: 2, name: "Thor", parent_id: 1, created_at: "2021-01-05 20:37:51", updated_at: "2021-01-05 20:37:51">, #<Person id: 3, name: "Balder", parent_id: 1, created_at: "2021-01-05 20:38:56", updated_at: "2021-01-05 20:38:56">]>
irb(main):002:0> Person.last.siblings
Person Load (0.2ms) SELECT "people".* FROM "people" ORDER BY "people"."id" DESC LIMIT ? [["LIMIT", 1]]
Person Load (0.2ms) SELECT "people".* FROM "people" WHERE "people"."parent_id" = ? AND "people"."id" != ? LIMIT ? [["parent_id", 1], ["id", 3], ["LIMIT", 11]]
=> #<ActiveRecord::AssociationRelation [#<Person id: 2, name: "Thor", parent_id: 1, created_at: "2021-01-05 20:37:51", updated_at: "2021-01-05 20:37:51">]>
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…