让我们说我正在看一起预约的医师和患者,并且我想过滤掉与user.id = 1的医师有关的约会。我的医师和患者存储在同一类中Users(有一个user_roles和角色表来区分它们,但这对本示例而言并不重要),并通过UserAppointments表将其与每个约会相关联,因此看起来大致像这样:
class User < ActiveRecord::Base
has_many :user_appointments
class UserAppointment < ApplicationRecord
belongs_to :user
belongs_to :appointment
class Appointment < ApplicationRecord
has_many :user_appointments
has_many :users, through: :user_appointments
我最初尝试使用类似Appointment.joins(:users).where.not("users.id = 1")
的方法,但是包括用户1在内的任何约会仍然有一个有效的患者与其连接,因此它将在患者的UserAppointment条目上进行内部联接并包括该约会的记录。有效约会在该查询中出现两次,因为两个用户有两个UserAppointment条目。
因此,我可以为出现两次的任何Appointment.id设置过滤器(表明所涉及的医生不是用户1)或创建涉及用户1的约会列表,然后直接将其过滤掉。但是我只是想知道是否有一个类似于.where.not
的命令,如果匹配了任何条件,即使有其他不符合条件的有效子代,也可以排除约会。
答案 0 :(得分:1)
Appointment.joins(users: :roles).where(roles: {code: :physician}).where.not(users: {id: 1})
这样,您就可以为每个医师计算一次约会。 (用您的code
表中的等效列替换roles
)
尽管如此,您似乎说约会总是在患者和用户之间进行。如果是这样,那么以下架构可能会更适合:
class User < ActiveRecord::Base
has_many :user_appointments
class Appointment < ApplicationRecord
belongs_to :patient, class_name: 'User' # needs a patient_id foreign key
belongs_to :physician, class_name: 'User' # needs a physician_id foreign key
然后您可以查询Appointment.where.not(physician_id: 1)
编辑帖子评论:
例如,如果您想获得10号患者的所有约会,而排除1号和2号医生的约会,则可以采用以下方法:
class Appointment < ApplicationRecord
scope :joins_physician, -> { joins(users: :roles).where(roles: {code: :physician}) }
scope :joins_patient, -> { joins(users: :roles).where(roles: {code: :patient}) }
scope :excluding_physicians, -> (*physician_ids) { where.not(id: unscoped.joins_physician.where(users: {id: physician_ids})) }
scope :for_patients, -> (*patient_ids) { where(id: unscoped.joins_patient.where(users: {id: patient_ids})) }
end
Appointment.for_patients(1).excluding_physicians(1,2)
如您所见,对于某些本应简单的事情,它开始变得异常复杂。怪异来自模型结构,没有反映Appointment
,User
和User
患者之间的业务关联。