Как выбрать все roots + nested children одним запросом?
Или лучше, если рисуешь список категорий, каждый раз в roots.each
обращаться к методу children?
Заранее благодарен,
Дмитрий
Вообще от задачи зависит, соственно дерево комментариев вывести, по
дереву лазит и не надо просто отступ делаешь ориентируясь на level. ну
или в переборе учитывешь текущий level тогда можно вывести вложенные
структуры, html'ные списки например. Меню туда же в принципе.
On 5 окт, 02:36, "Dmitry Polushkin" <dmitry.polush...@gmail.com>
wrote:
> Если я выберу таким образом, то все доступные методы, вроде roots,
> children и прочих будут недоступны.
> Как мне пройтись по дереву?
>
current_level = 0
Category.each do |cat|
if cat.level > current_level then
puts "<ul>\n"
puts "<li>#{cat.name}</li>\n"
current_level += 1
elsif cat.level == current_level then
puts "<li>#{cat.name}</li>\n"
elsif cat.level < current_level then
puts "</ul>\n"
puts "<li>#{cat.name}</li>\n"
current_level -= 1
end
end
может в коде есть ошибки я на запускал, но примерно так
On 5 окт, 19:51, "Dmitry Polushkin" <dmitry.polush...@gmail.com>
wrote:
> Отрисовать дерево - это не есть проблема. Проблемма лежит в
> оптимизации. Каждрый раз при запросе к Category.roots.each {
> |category| category.children } базе посылается запрос. К сожалению это
> нагружает не только базу данных, но ещё и рельсовое приложение. Мне же
> хочется, что бы для вызвращения всех категорий (и рутовых, и чайлдов)
> был послан всего один запрос.
>
Разве это красота ? Вот это - красота:
<%= render :partial => 'tree', :locals => { :items => @posts } %>
а в _tree.html.erb
<ul>
<% items.each_with_children do |item, children| %>
<li>
<span class="title"><%= item.title %></span>
<%= render :partial => 'tree', :locals => { :items => children } %>
</li>
<% end %>
</ul>
Вся магия - в хитрой коллекции-обертке.
On 5 окт, 23:07, "Maxim Kulkin" <maxim.kul...@gmail.com> wrote:
<%= render :partial => "layouts/categories", :locals => { :categories
=> Category.roots, :root => true } %>
и в файле части:
<ul<% if root %> id="categories"<% end %>>
<% categories.each do |category| %>
<li>
<%= category.name %>
<% if category.children_count > 0 %>
<%= render :partial => "layouts/categories", :locals => {
:categories => category.children } %>
<% end %>
</li>
<% end %>
</ul>
Но что меня тут настораживает:
category.children_count - один запрос
category.children - ещё один
И так в каждой итерации.
Пример Zork-а мне абсолютно не нравится, как то банально... тем более
откуда level берётся - не понятно. Конечно, его можно вычислить через
массив parent'ов и сравнение parent'ов... но это всё ещё сильнее
усложняет.
Вполне возможно, есть другой вариант, использовать один root элемент,
и делать с него full_set. Но быть может сделать full_set можно не с
какого-либо root node, а прямо с настоящего корня, т.е. где у всех
node'ов parent_id IS NULL?
<ul<% if root %> id="categories"<% end %>> тут надо <% if root? %>,
иначе тоже обращение к базе будет.
насчет full set это конечно можно, но тут "настоящего корня" у
вложенных множеств нет, потому что может быть несколько корней и в них
parent_id = 0
и вообще parent_id это вспомогательный параметр, для дерева во
вложенных множествах достаточно левого и правого ключа.
Если делать красивую реализацию как у Maxim Kulkin, то нужно создать
прокси объект. имеющий рекурсивную структуру (то есть каждый такой
объект может содержать набор таких же объектов) и реализовать у него
методы типа children.
тогда получится что ты будешь вызывать методы не у модели которая
реализует дерево (и при вызове children лезет в базу), а у своего
объекта, который содержит в себе все дерево, и собственно в базу не
лезет...
On 5 окт, 23:31, "Dmitry Polushkin" <dmitry.polush...@gmail.com>
wrote:
> On 10/5/07, Maxim Kulkin <maxim.kul...@gmail.com> wrote:
Это то понятно, что можно... единственное что меня сдерживало от
написания подобного метода, или кеширования это то, что быть может
кто-нибудь уже сталкивался с подобной проблемой и решил её
каким-нибудь ещё более изящным способом, да или же просто, кто то уже
до меня реализовал этот метод, который сразу же грузит все ветки.
On 10/5/07, Zork <zo...@nwgsm.ru> wrote:
On 6 окт, 00:35, "Dmitry Polushkin" <dmitry.polush...@gmail.com>
wrote:
> Чем моя реализация отличается от реализации Максима Кулкина? :))
>
> Это то понятно, что можно... единственное что меня сдерживало от
> написания подобного метода, или кеширования это то, что быть может
> кто-нибудь уже сталкивался с подобной проблемой и решил её
> каким-нибудь ещё более изящным способом, да или же просто, кто то уже
> до меня реализовал этот метод, который сразу же грузит все ветки.
>
Да, тоже неплохо.
Когда я писал свою реализацию, мне a) не хотелось писать доп.
прокси-объект на каждый элемент коллекции (ровно как и подмешивать
children в существующие - мало ли, может там уже такое есть и я
перетру существующий своим); b) не хотелось на каждый элемент
порождать еще один объект-обертку - не выгодно по памяти (использовать
один и тот же объект тоже, имхо, неудобно).
У меня по одному экземпляру прокси на каждую подветку, при этом массив
используется всегда исходный, никаких копирований и т.п.
Дешево и сердито.
> Это то понятно, что можно... единственное что меня сдерживало от
> написания подобного метода, или кеширования это то, что быть может
> кто-нибудь уже сталкивался с подобной проблемой и решил её
> каким-нибудь ещё более изящным способом, да или же просто, кто то уже
Видел как кэшируют. Имхо, не айс.
> до меня реализовал этот метод, который сразу же грузит все ветки.
Ага, надо встроить внутрь AR его.
Это известная фигня, что оно якобы будет работать медленнее. Я считаю,
что это не то место, где нужно жертвовать чистотой и красотой в пользу
производительности. По крайней мере не на тех объемах, для которых
писал это я.
>
> Это известная фигня, что оно якобы
> будет работать медленнее. Я считаю,
> что это не то место, где нужно
> жертвовать чистотой и красотой в
> пользу
> производительности. По крайней мере
> не на тех объемах, для которых
> писал это я.
Мне конечно стыдно со своим рылом в
калашный ряд (у меня сет не better а
простой vanilla)
# Returns a set of all of its children and nested children
def all_children
self.class.find(:all,
:conditions => "#{scope_condition} AND #{root_column} = #{self
[root_column]} AND #{left_col_name} > #{self[left_col_name]} AND #
{right_col_name} < #{self[right_col_name]}",
:order => 'lft ASC' )
end
а дальше
<% @categories.each do | category | %>
<h5><%= checkbox_for_category(category) %> <%= h
category.name %></h5>
<% category.all_children.each do | sub_category | %>
<div style='margin-left: <%= sub_category.depth %>em'>
<%= checkbox_for_category(sub_category) %> <%= h
sub_category.name %>
</div>
<% end %>
<% end %>
вторая часть это камень в огород
рекурсивистов
ну не будет вложенных UL и что? кто
скончается от этого?
--
Julian 'Julik' Tarkhanov
please send all personal mail to
me at julik.nl
Я, кстати, тоже использовал обычный nested_set, потому что мне его
функционала вполне хватало (мне не нужно было переносить элементы из
одного места в дереве в другое, называть столбцы я мог как хотел)...
On 6 окт, 11:00, Julian 'Julik' Tarkhanov <julian.tarkha...@gmail.com>
wrote:
On 7 окт, 11:57, "Maxim Kulkin" <maxim.kul...@gmail.com> wrote:
> On 10/6/07, Zork <z...@nwgsm.ru> wrote:> У него (better nested set) есть level, вместо depth. Метод для вывода