Я смоделировал, Пользователь имеет участие в событии.
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.
Я хочу получить все события для конкретного пользователя, где visit_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) USE MERGE
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) Есть ли способ сказать Active Record игнорировать объединения, если они уже произошли?