Учитывая эти две модели
class Article < AR::Base
belongs_to :tag
default_scope order('id DESC')
end
class Tag < AR::Base
has_many :articles
scope :featured, order(:ordering).limit(5)
end
Я пытаюсь объединить эти две таблицы таким образом, чтобы я мог получить список рекомендуемых тегов и для каждой из них последнюю статью в этом теге содин запрос, что-то вроде
Tag.featured.each do |tag|
p tag.name
p tag.articles.first.title # this will fetch the article in the tag with the highest id
end
Написанный таким образом, этот код имеет проблему запроса (n + 1) , я пытаюсь оптимизировать его, потому что он будет выполняться очень часто,Я исключил вызов includes
в области действия featured
, так как он загрузит все Article
в первых 5 тегах (много статей ...)
В простом старом SQL я могусоединить эти две таблицы, используя запрос типа
SELECT tag_id, MAX(id) FROM articles GROUP BY tag_id
# or in Rails
Article.select('MAX(id), tag_id').group(:tag_id)
+--------+---------+
| tag_id | MAX(id) |
+--------+---------+
| 14 | 26787 |
...
| 1 | 27854 |
| 5 | 27780 |
| 0 | 10953 |
+--------+---------+
как таблицу объединения. Я могу получить все данные одним запросом.
Как перенести это в Rails и ActiveRecord?
update
Полный запрос, который мне нужно выполнить в контексте AR:
SELECT a.*, t.*
FROM tags t
JOIN (SELECT MAX(id) AS latest, tag_id FROM articles GROUP BY tag_id) j ON j.tag_id = t.id
JOIN articles p ON j.latest = a.id
LIMIT 5
Я попытался AR#find_by_sql
метод с последним запросом, я получаюправильный набор результатов, но тогда я не могу перемещаться по объектам
sql = '...' # This holds the previous query
Tag.find_by_sql(sql).first.class
=> "Tag"
Tag.find_by_sql(sql).first.articles.first
=> nil # why???
update 2
Пробовал также с
Tag.joins('JOIN ... all my query join part here ...').first.articles.first
=> nil
Однако я заметил, что могуиспользовать мое поле статей напрямую как поля тегов, т.е. я могу написать
Tag.find_by_sql(...).first.title # where title is a field of Article class
Tag.joins(...).first.title # where title is a field of Article class
, но, очевидно, я не могу вызывать Article
методы экземпляра.