Обновление Rails включает изменение поведения метода

Я копал пару дней и не нашел хорошего объяснения этому изменению поведения. Я нахожусь в процессе обновления приложения Rails с 3.2 до 5.2, это код в прохождении теста из моего приложения rails 3.

 ps = Project.includes(:rentals).where('rentals.id IN (?)', [1,2,3,4])

это выплевывает большой старый левый SQL-запрос.
но если я делаю тот же запрос в рельсах 5, я получаю ошибку MySQL

ActiveRecord::StatementInvalid (Mysql2::Error: Unknown column 'rentals.id' in 'where clause': SELECT  `projects`.* FROM `projects` WHERE (rentals.id IN (1,2,3,4)) LIMIT 11 /*application:ConHQ*/)

Насколько я понимаю, включает в себя то, что он должен выполнять отдельные запросы, если на включенную таблицу не ссылаются в предложении where, и в этом случае он должен выполнить левое соединение. но, похоже, здесь этого не происходит. использование eager_load работает в этом случае:

 ps = Project.eager_load(:rentals).where('rentals.id IN (?)', [1,2,3,4])

но я думал, что включает в себя то же самое.
Я также заметил, что иногда include выполняет тот же запрос, что и eager_load

@project = Project.find(174)
@project.rentals.eager_load(:equipment_name).where('equipment_names.id IN (?)', [1,2,3,4])
@project.rentals.includes(:equipment_name).where('equipment_names.id IN (?)', [1,2,3,4])

В этом случае eager_load и включает оба выполняют левое соединение. Я не нашел никакой документации, которая объясняет, почему в таких ситуациях действует по-разному. как именно включает в себя выбрать запрос, который он выполняет?

1 ответ

Решение

includes просто говорит ActiveRecord, что данные должны быть загружены с нетерпением, но он может достичь этого, как ему нравится. Если вы хотите сослаться на другую модель в запросе, вам придется использовать references(:rentals), тоже.

ActiveRecord API является чрезвычайно мощным и универсальным, но, как это часто бывает с Ruby и его библиотеками, есть много способов чего-то достичь. В этом случае вы также можете использовать merge слиться в другом отношении.

rentals = Rental.where(id: [1,2,3,4])
projects = Project.joins(:rentals).merge(rentals) # you can additionally add includes, too, if you want to access the rentals

Это дает дополнительное преимущество: вам не нужно заботиться о названии таблицы Rental модель.

Другие вопросы по тегам