Я столкнулся с проблемой N + 1 по ассоциации:
class Category < ApplicationRecord
has_many :categories_designs, dependent: :destroy
has_many :designs, through: :categories_designs
has_many :templates, ->{ where(is_template: true) }, through: :categories_designs, class_name: 'Design', source: :design
def marked_designs_as_new?
designs.select(:mark_design_as_new_until).where("mark_design_as_new_until >= ?", Time.now.in_time_zone.beginning_of_day).exists?
end
end
И я хочу использовать в представлении метод marked_designs_as_new?
.
- @categories.each do |category|
= category.title.titleize
- if category.marked_designs_as_new?
.design-type-marked
NEW
В моем контроллере я вызываю:
@categories = Category.includes(categories_designs: :design).visible
И я столкнулся с проблемой N + 1.
Category Load (0.4ms) SELECT "categories".* FROM "categories" WHERE "categories"."hidden" = $1 ORDER BY "categories"."position" ASC LIMIT $2 OFFSET $3 [["hidden", false], ["LIMIT", 100], ["OFFSET", 0]]
CategoriesDesign Load (0.4ms) SELECT "categories_designs".* FROM "categories_designs" WHERE "categories_designs"."category_id" IN (1, 3, 4, 5, 6, 7, 8)
Design Load (0.5ms) SELECT "designs".* FROM "designs" WHERE "designs"."id" IN (1, 4, 3, 6)
(0.7ms) SELECT COUNT(*) FROM "designs" INNER JOIN "categories_designs" ON "designs"."id" = "categories_designs"."design_id" WHERE "categories_designs"."category_id" = $1 AND "designs"."is_template" = $2 [["category_id", 1], ["is_template", true]]
Design Exists (0.7ms) SELECT 1 AS one FROM "designs" INNER JOIN "categories_designs" ON "designs"."id" = "categories_designs"."design_id" WHERE "categories_designs"."category_id" = $1 AND (mark_design_as_new_until >= '2018-03-13 00:00:00') LIMIT $2 [["category_id", 1], ["LIMIT", 1]]
(0.5ms) SELECT COUNT(*) FROM "designs" INNER JOIN "categories_designs" ON "designs"."id" = "categories_designs"."design_id" WHERE "categories_designs"."category_id" = $1 AND "designs"."is_template" = $2 [["category_id", 3], ["is_template", true]]
............. etc.
Зачем?
2 ответа
Хорошо, ваш .select(:mark_design_as_new_until)
выполняет еще один запрос к базе данных. Что вам следует сделать, так это использовать метод выбора массива следующим образом:
.select(&:mark_design_as_new_until)
Это дает вам массив дизайнов, загруженных в память, в котором вы можете выполнить метод .any?
для проверки вашего состояния:
.select(&:mark_design_as_new_until).any? { |design| design.mark_design_as_new_until >= Time.now.in_time_zone.beginning_of_day }
И, конечно же, включите designs
в свою категорию.
Category.includes(:designs, ...)
Вы пробовали Category.includes([:categories_designs, :design])
Кроме того, вы можете изменить метод marked_designs_as_new?
следующим образом:
def marked_designs_as_new?
designs.select{ |x| x.marked_designs_as_new? }.any?
end
design.rb
class Design
def marked_designs_as_new?
mark_design_as_new_until >= Time.now.in_time_zone.beginning_of_day
end
end
Похожие вопросы
Новые вопросы
ruby-on-rails
Ruby on Rails - это полнофункциональная платформа веб-приложений с открытым исходным кодом, написанная на Ruby. Он следует популярной модели фреймворка MVC и известен своим подходом «соглашение поверх конфигурации» при разработке приложений.