dbo*_*d68 11 activerecord 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}
Run Code Online (Sandbox Code Playgroud)
我的问题是关于范围查询和最佳实践.
我已将大部分范围查询放在Event上.
我想获得READ_status = 0的特定用户的所有事件
user = User.find(...)
user.events.is_attending
Run Code Online (Sandbox Code Playgroud)
从逻辑上讲,我认为,这是最好的,也是最有意义的
然而,这将给我一个双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
Run Code Online (Sandbox Code Playgroud)
显然,这会产生重复,这不是我想要的.
所以我知道我可以做的选择
1)使用MERGE
Event
scope :for_user, -> (user){ joins(:attendances).where(attendances: {user: user})}
Run Code Online (Sandbox Code Playgroud)
然后打电话
Event.for_user(user).merge(Event.is_attending)
Run Code Online (Sandbox Code Playgroud)
这给了我sql
SELECT "events".* FROM "events" INNER JOIN "attendances" ON "attendances"."event_id" = "events"."id" WHERE "attendances"."user_id" = 59 AND "attendances"."attend_status" = 0
Run Code Online (Sandbox Code Playgroud)
这就是我要的.但这似乎是可怕的语法,令人困惑.
2)使用包括
如果我使用包含而不是加入,我不会重复加入.因为它分别加载事件并且足够聪明而不能复制.
Event
scope :is_attending, -> { includes(:attendances).where(attendances: {attend_status: Attendance.attend_statuses[:attending] })}
Run Code Online (Sandbox Code Playgroud)
但是我不想急于加载.
3)ASSUME表已经在范围之外加入
最后我可以假设表已经在调用范围之外加入了,
Event
scope :is_attending, -> { where(attendances: {attend_status: Attendance.attend_statuses[:attending] })}
Run Code Online (Sandbox Code Playgroud)
但这对我来说似乎有点愚蠢的设计,并使这个命名范围不再可用.
所以我的问题
1)最好的方法是什么?最符合逻辑的
user.events.is_attending是我理想要使用的那个.
2)有没有办法告诉Active Record如果已经发生了忽略连接?
我会使用接近您的第一个建议的东西,除了我会直接在您的内部模型(出勤)上合并范围。
所以而不是:
Event.for_user(用户).merge(Event.is_attending)
我会选择:
Event.for_user(用户).merge(Attendance.is_attending)
这是一个清晰的语法。您的 is_attending 范围不需要有连接,每个类负责了解如何过滤自身。
如果你经常使用它,你可以创建一个for_attending_user(user)范围来隐藏合并:
class Event
scope :for_attending_user, -> user { for_user(user).merge(Attendance.is_attending) }
...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1280 次 |
| 最近记录: |