我已经建模,用户在活动中出席了会议.
class User has_many :attendances has_many :events,through: :attendances class Event has_many :attendances scope :is_attending,-> { joins(:attendances).where(attendances:{attend_status: Attendance.attend_statuses[:attending] })} class Attendance belongs_to :event belongs_to :user enum attend_status: { attending: 0,not_attending: 1}
我的问题是关于范围查询和最佳实践.
我把大部分的范围查询都放在了Event上.
user = User.find(...) user.events.is_attending
逻辑上我会想,这是最好的,最有意义
不过这会给我一个双重的内在联系
SELECT "events".* FROM "events" INNER JOIN "attendances" "attendances_events" ON "attendances_events"."event_id" = "events"."id" INNER JOIN "attendances" ON "events"."id" = "attendances"."event_id" WHERE "attendances"."user_id" = $1 AND "attendances"."attend_status" = 0
显然这会创造出不是我想要的重复项.
所以选择我知道我可以做
1)使用合并
Event scope :for_user,-> (user){ joins(:attendances).where(attendances: {user: user})}
然后打电话
Event.for_user(user).merge(Event.is_attending)
这给了我sql
SELECT "events".* FROM "events" INNER JOIN "attendances" ON "attendances"."event_id" = "events"."id" WHERE "attendances"."user_id" = 59 AND "attendances"."attend_status" = 0
这就是我想要的
但这似乎是可怕的语法,令人困惑.
2)使用包括
如果我使用include而不是join,我不会得到重复加入.由于它分开加载事件,并且足够聪明,无法重复.
Event scope :is_attending,-> { includes(:attendances).where(attendances: {attend_status: Attendance.attend_statuses[:attending] })}
但是我不想加载.
3)ASSUME表已经加入到范围之外
最后我可以假设表已经加入了调用范围之外,
Event scope :is_attending,-> { where(attendances: {attend_status: Attendance.attend_statuses[:attending] })}
但这似乎对我来说有点愚蠢的设计,使得这个命名范围不太可用.
所以我的问题
1)最好的方法是什么?
最合乎逻辑的
user.events.is_attending是我最理想的用途.
2)有没有办法告诉活动记录忽略连接,如果他们已经发生了?
解决方法
我会使用接近你的第一个建议的东西,除了我将范围直接合并到你的内部模型(Attendance)上.
所以而不是:
Event.for_user(用户).merge(Event.is_attending)
我会去:
Event.for_user(用户).merge(Attendance.is_attending)
这是一个清晰的语法.您的is_attending范围不需要连接,每个类都负责了解如何过滤自身.
如果经常使用它,您可以创建一个for_attending_user(用户)范围来隐藏合并:
class Event scope :for_attending_user,-> user { for_user(user).merge(Attendance.is_attending) } ...