Как сделать условную загрузку в ActiveRecord?

У меня есть тег модели, который является моделью дерева (используя closure_tree) и благодаря жемчужине я могу делать такие вещи, как:

Tag.includes(:children).first

чтобы загружать своих детей. Теперь у меня есть метод экземпляра, который также использует детей. Поэтому, когда я получаю тег по указанному запросу, перебираем тег и его дочерние элементы и вызываем этот метод экземпляра, bullet Джем жалуется, что я делаю N+1 запросов и советует мне include(children), Это происходит потому, что я не загрузил дочерние элементы дочерних элементов, поэтому при вызове метода экземпляра я делаю отдельный запрос для дочерних элементов каждого вложенного тега тега первого уровня.

Я могу решить это, сделав следующее:

Tag.includes(children: :children).first

В этом случае ActiveRecord активно загружает тег, его дочерние элементы и дочерние элементы его дочерних элементов. Это, однако, работает, если есть только 3 поколения - тег - это дедушка и бабушка, а затем приходят родители (которые являются дочерними элементами корневого тега) и внуки (которые являются дочерними элементами корневого тега). Если у меня, скажем, 4 поколения, то я должен сделать:

Tag.includes(children: {children: :children}).first

Так что, если я могу определить depth самого дальнего внука корневого тега, есть ли способ условно построить мой запрос - если глубина равна 2, используйте includes(:children), если глубина 3 - используйте includes(children: :children) и так далее?

2 ответа

Судя по документации по адресу: https://github.com/mceachen/closure_tree вы должны использовать

Tag.descendants
Tag.self_and_descendants

Это извлечет все дочерние элементы, дочерние элементы и т. Д., Пока не закончится на листе.

Лучшее решение, которое я мог придумать, это:

  def included_children(tag_id)
    depth = Tag.find(tag_id).leaves.last.depth
    eval(includes_string(depth))
  end

  def includes_string(depth)
    "{children: #{depth > 1 ? includes_string(depth - 1) : ':children'}}"
  end

Я сначала нахожу depth из самого глубокого отпуска. Это говорит мне, сколько раз я должен позвонить :children, Затем я строю строку на основе глубины и оцениваю строку в коде, которую я использую в includes метод. Любые предложения по улучшению приветствуются, потому что у этого решения есть несколько недостатков, и я считаю его совершенно нечистым. Спасибо.

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