Ecco la soluzione che ho scelto. Il trucco consisteva nell'usare left outer join
(comando ruby desidero_load) per gli utenti e la tabella block_date_periods, e includendo quegli utenti il cui campo data_inizio nella tabella unita è NULL, ovviamente perché non hanno alcun oggetto data bloccato associato a se stessi. La query che uso:
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
Ho dovuto aggiungere e sottrarre 1 ora dalla data di inizio e di fine perché la query non voleva includere date di fine esatte per qualche motivo, in modo che il 26-12-2015 non fosse incluso nel periodo dal 22-12-2015 al 16-12-2015 per qualche motivo devo ancora capire.
Per qualche motivo non mi piace quella soluzione e vorrei sapere se esiste una query migliore e più veloce di quella che ho io.