带条件的 Rails 自连接仅适用于父级



以 http://guides.rubyonrails.org/association_basics.html#self-joins 为例,

class Employee < ApplicationRecord
has_many :subordinates, class_name: "Employee", foreign_key: "manager_id"
belongs_to :manager, class_name: "Employee"
end

如果我想应用于一个条件,比如说,只有具有is_manager的员工(假设员工有这样的布尔字段(是正确的,是经理并且可以显示下属

如果我只是将上面更改为下面

class Employee < ApplicationRecord
has_many :subordinates, -> {where is_manager: true}, class_name: "Employee", foreign_key: "manager_id"
belongs_to :manager, class_name: "Employee"
end

它不起作用,因为条件where is_manager: true也适用于subordinates

FROM `employees` WHERE `employees`.`is_manager` = 1 AND (employees.manager_id = 1)

但我只想申请经理,而不是下属。

类似的东西

Employee.where(manager_id: employee.where(is_manager: true))

所以,如果我打电话

employee = Employee.find 1 
employee.subordinates

首先,它将检查员工是否是经理,如果是,则返回下属;否则,返回空数组

为什么不创建一个类方法[1],as_manager.像这样:

class Employee < ApplicationRecord
has_many :subordinates, class_name: "Employee", foreign_key: "manager_id"
belongs_to :manager, class_name: "Employee"
class << self
def as_manager
where(is_manager: true)
end
end
end

然后你应该能够做到:

Employee.as_manager.subordinates

或者,鉴于您的"业务需求"(非常奇怪的是,业务会对这种级别的实现细节有要求(,您如何抢占has_many指令提供的subordinates方法?

class Employee < ApplicationRecord
has_many :subordinates, class_name: "Employee", foreign_key: "manager_id"
belongs_to :manager, class_name: "Employee"
def subordinates
is_manager ? where(manager_id: id) : []
end
end

这样,您可以保留has_many提供的所有其他方法,但获得您想要的行为subordinates.

[1] Jörg W Mittag希望声明:

我是那些喜欢指出Ruby中没有类方法的Ruby纯粹主义者之一。不过,我完全可以口语地使用术语类方法只要各方都完全理解它是一种口语用法。换句话说,如果您知道没有类方法这样的东西,并且术语"类方法"只是"作为Class实例的对象的单例类的实例方法"的缩写,那么就没有问题。但除此之外,我只看到它阻碍了理解。

让各方充分理解,上面使用的术语类方法在其口语意义上。

最新更新