Si può fare un po 'meglio di quello che Adam Lassek ha proposto anche se è sulla strada giusta. Ho appena risolto un problema simile cercando di ottenere un elenco di amici da un modello di social network. Gli amici possono essere acquisiti automaticamente in vari modi, ma mi piacerebbe avere un metodo di query amichevole ActiveRelation in grado di gestire ulteriori concatenazioni. Così ho
class User
has_many :events_as_owner, :class_name => "Event", :inverse_of => :owner, :foreign_key => :owner_id, :dependent => :destroy
has_many :events_as_guest, :through => :invitations, :source => :event
def friends
friends_as_guests = User.joins{events_as_guest}.where{events_as_guest.owner_id==my{id}}
friends_as_hosts = User.joins{events_as_owner}.joins{invitations}.where{invitations.user_id==my{id}}
User.where do
(id.in friends_as_guests.select{id}
) |
(id.in friends_as_hosts.select{id}
)
end
end
end
che sfrutta il supporto di subquery di Squeels. SQL generato è
SELECT "users".*
FROM "users"
WHERE (("users"."id" IN (SELECT "users"."id"
FROM "users"
INNER JOIN "invitations"
ON "invitations"."user_id" = "users"."id"
INNER JOIN "events"
ON "events"."id" = "invitations"."event_id"
WHERE "events"."owner_id" = 87)
OR "users"."id" IN (SELECT "users"."id"
FROM "users"
INNER JOIN "events"
ON "events"."owner_id" = "users"."id"
INNER JOIN "invitations"
ON "invitations"."user_id" =
"users"."id"
WHERE "invitations"."user_id" = 87)))
Un modello alternativo in cui avete bisogno di un numero variabile di componenti è dimostrata con una leggera modifica al codice di cui sopra
def friends
friends_as_guests = User.joins{events_as_guest}.where{events_as_guest.owner_id==my{id}}
friends_as_hosts = User.joins{events_as_owner}.joins{invitations}.where{invitations.user_id==my{id}}
components = [friends_as_guests, friends_as_hosts]
User.where do
components = components.map { |c| id.in c.select{id} }
components.inject do |s, i|
s | i
end
end
end
Ed ecco un occhio e croce per quanto riguarda la soluzione per il domanda esatta di OP
class Shift < ActiveRecord::Base
def self.limit_per_day(options = {})
options[:start] ||= Date.today
options[:stop] ||= Date.today.next_month
options[:per_day] ||= 5
queries = (options[:start]..options[:stop]).map do |day|
where{|s| s.scheduled_start >= day}.
where{|s| s.scheduled_start < day.tomorrow}.
limit(options[:per_day])
end
where do
queries.map { |c| id.in c.select{id} }.inject do |s, i|
s | i
end
end
end
end
Questo è un caso leggermente diverso, tuttavia. Devo essere in grado di concatenare un numero arbitrario di selezioni insieme. Quindi dovrò ancora ricorrere all'interpolazione delle stringhe indipendentemente dal fatto che io usi 'UNION' o' OR'. A meno che tu non possa suggerire un modo per farlo con Squeel/ARel? –
Questo può essere fatto. Richiede solo un po 'di magia da squeel. Fammici pensare. Probabilmente si potrebbe fare con Enumerable inject. Ci provo e aggiorno la risposta se funziona. – bradgonesurfing
Ok. Ho creato una funzione equivalente che mette i componenti in una matrice prima e poi combina quei componenti.Ricorda solo che SQueel è semplicemente un rubino con qualche metodo che manca di magia. Puoi fare il ruby normale all'interno dei blocchi dove e creare query in modo dinamico. – bradgonesurfing