Oto rozwiązanie, które wybrałem. Sztuczka polegała na użyciu left outer join
(polecenie ruby eager_load) dla użytkowników i tabeli zablokowanych_datów_okresów, a także tych użytkowników, których pole data_początkowa w połączonej tabeli ma wartość NULL, oczywiście dlatego, że nie mają żadnych powiązanych obiektów z blokowanymi datami. Zapytanie, którego używam:
User.eager_load(:blocked_date_periods).
where("blocked_date_periods.start_date is null OR
not tsrange(
blocked_date_periods.start_date - '00:59:59'::interval,
blocked_date_periods.end_date + '00:59:59'::interval
) @> ?::timestamp",
Date.parse(DATE_STRING)).count
Musiałem dodać i odjąć 1 godzinę od daty rozpoczęcia i zakończenia, ponieważ zapytanie z jakiegoś powodu nie chciało obejmować dokładnych dat zakończenia, więc 12-26-2015 nie znalazło się w okresie od 22-22-2015 do 12-16-2015 z jakiegoś powodu jeszcze nie rozumiem.
Z jakiegoś powodu nie lubię tego rozwiązania i chciałbym wiedzieć, czy istnieje zapytanie, które jest lepsze i szybsze niż to, które mam.