Ho modellato, Utente ha presenze in un evento.Concatenamento ambito record attivo, ignora join, se già iscritto
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}
La mia domanda riguarda query mirate e best practice.
Ho messo la maggior parte delle mie query sull'oscilloscopio sull'evento.
voglio ottenere tutti gli eventi per un utente specifico in cui attend_status = 0
user = User.find(...)
user.events.is_attending
Logicamente penserei, questa legge il migliore e ha più senso
Tuttavia che mi avrebbe dato un doppio 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
Ovviamente questo crea duplicati che non è quello che volevo.
Così opzioni so che posso fare
1) USO MERGE
Event
scope :for_user, -> (user){ joins(:attendances).where(attendances: {user: user})}
quindi chiamare
Event.for_user(user).merge(Event.is_attending)
che mi dà la sql
SELECT "events".* FROM "events" INNER JOIN "attendances" ON "attendances"."event_id" = "events"."id" WHERE "attendances"."user_id" = 59 AND "attendances"."attend_status" = 0
Questo è ciò che Voglio. Ma questa sembra una sintassi terribile e confonde.
2) USO COMPRENDE
Se uso include, invece di unire, non vengo duplicato unisco. Poiché carica eventi separatamente ed è abbastanza intelligente da non duplicare.
Event
scope :is_attending, -> { includes(:attendances).where(attendances: {attend_status: Attendance.attend_statuses[:attending] })}
Tuttavia, non desidero caricare carico.
3) assumere tabella è già unito al di fuori del campo di applicazione
Finalmente posso supporre che la tabella è già unito al di fuori di chiamare il campo di applicazione,
Event
scope :is_attending, -> { where(attendances: {attend_status: Attendance.attend_statuses[:attending] })}
ma questo sembra il design un pò sciocco a me, e rende meno riutilizzabile questo ambito denominato.
Così le mie domande
1) Qual è l'approccio migliore per questo? Il più logico user.events.is_attending
è quello che idealmente voglio usare.
2) C'è un modo per dire a Active Record di ignorare i join se sono già accaduti?