让我们说我正在看医生和病人一起预约约会,我想过滤掉医生与user.id = 1的约会。我的医生和病人存放在同一个班级用户(有一个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
的命令,如果匹配任何条件,可以排除约会,即使它有其他有效的孩子与条件不匹配。
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
病人之间的商业关联。