Вам нужно выходное соединение и выберите результаты, в которых внешнее соединение создало NULL.
Вам понадобится SQL:
SELECT bankholidays.*
FROM bankholidays
LEFT OUTER JOIN working_bankholidays on bankholidays.id = working_bankholidays.bankholiday_id
AND working_bankholidays.person_id = 111
WHERE working_bankholidays.id is NULL
Проблема в том, что вынеобходимо условие для person_id
в предложении FROM
.Если он находится в предложении WHERE
, вы получите другие результаты.
Когда он находится в предложении FROM, он будет использовать условие для обработки таблицы working_bankholidays
, как если бы в ней были только строки ссоответствие person_id
.Он делает это перед выполнением внешнего соединения, поэтому, если нет записей с совпадающим person_id
, он добавит записи из внешнего соединения со значениями NULL во всех полях таблицы working_bankholidays
.
К сожалению, я не знаю никакого способа сделать это с активными ассоциациями записи.Все активные ассоциации записей помещают условия в предложение WHERE
, а не в предложение FROM
.
Если вы измените has_many_and_belongs_to_many
на «сквозные», и вы сделаете это:
class Person
def free_bankholidays
Bankholiday.left_joins(:working_bankholidays).where(working_bankholidays: {id: nil, person_id: self.id})
end
это даст вам следующее:
SELECT bankholidays.*
FROM bankholidays
JOIN working_bankholidays on bankholidays.id = working_bankholidays.bankholiday_id
WHERE working_bankholidays.id is NULL
AND working_bankholidays.person_id = 111
, которое даст вам разные и неправильные результаты.
РЕДАКТИРОВАТЬ:
См. Комментарий engineermnky.Я еще не пробовал, поэтому я не готов включить это в свой ответ.