gpt4 book ai didi

ruby-on-rails - Active Record 作用域链,忽略连接,如果已经连接

转载 作者:行者123 更新时间:2023-12-03 09:24:30 25 4
gpt4 key购买 nike

我已经建模,用户在一个事件中有出席。

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}

我的问题是关于范围查询和最佳实践。

我已将大部分范围查询放在事件上。

我想获取某个特定用户的所有事件,其中attend_status = 0
user = User.find(...)
user.events.is_attending

从逻辑上讲,我认为,这读起来最好,也最有意义

但是,这会给我一个双重 INNER JOIN
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) 用途包括

如果我使用includes 而不是join,我不会得到重复的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) 有没有办法告诉 Active Record 忽略已经发生的连接?

最佳答案

您可以添加与 is_attending 的关联条件到 User模型:

class Attendance < ActiveRecord::Base
belongs_to :event
belongs_to :user
enum attend_status: { attending: 0, not_attending: 1}

scope :is_attending, -> { where(attend_status: attend_statuses[:attending]) }
end

class User < ActiveRecord::Base
has_many :attendances
has_many :events, through: :attendances

has_many :attending_events, -> { Attendance.is_attending }, through: :attendances, source: :event
end

现在您无需重复加入即可接收参加事件:
u.attending_events

SELECT "events".* FROM "events"
INNER JOIN "attendances" ON "events"."id" = "attendances"."event_id"
WHERE "attendances"."user_id" = 1 AND "attendances"."attend_status" = 0 [["user_id", 1], ["attend_status", 0]]

这种方法有一个缺点:你不能组合条件。但如果您正在使用状态列,这是有道理的。因为这种方法反射(reflect)了关系的逻辑。

关于ruby-on-rails - Active Record 作用域链,忽略连接,如果已经连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29294238/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com