ruby-on-rails – 活动记录范围链接,如果已经加入,则忽略连接

前端之家收集整理的这篇文章主要介绍了ruby-on-rails – 活动记录范围链接,如果已经加入,则忽略连接前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我已经建模,用户在活动中出席了会议.
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上.

我想获取att_status = 0的特定用户的所有事件

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) }
  ...

猜你在找的Ruby相关文章