rails
[[3]}właśnie podążałem za samouczkiem Railscast:
Http://railscasts.com/episodes/262-trees-with-ancestry
Czy możliwe jest paginowanie wyników z ułożonych przodków? eg: Given I have the following in my Message controller:
def index
@messages = Message.arrange(:order => :name)
end
Więc jak miałbym to paginować, ponieważ to spowoduje hash?
Update Znalazłem to, Jeśli używam .klawiszy wtedy będzie paginate, ale tylko najwyższy poziom nie dzieci.
Message.scoped.arrange(:order => :name).keys
Update Każda wiadomość ma kod i pewną treść. Mogę mieć zagnieżdżone wiadomości
Przypuśćmy, że mam
Kod-Nazwa
1 - Test1
1 - test1 sub1
2 - test1 sub2
2 - Test2
1 - test2 sub1
2 - test2 sub2
3 - test2 sub3
W ten sposób chcę wyświetlić listę, ale chcę również paginować to posortowane drzewo.
1 answers
Jest to możliwe, ale udało mi się to zrobić tylko przy użyciu dwóch wycieczek bazy danych.
Główny problem wynika z tego, że nie można ustawić limitów na dzieci węzła, co prowadzi do obcinania dzieci węzła lub osierocania dzieci na kolejnych stronach.
Przykład:
id: 105, Ancestry: Null
id: 117, Ancestry: 105
id: 118, Ancestry: 105/117
id: 119, Ancestry: 105/117/118
LIMIT 0,3 (dla przykładu powyżej) zwróci trzy pierwsze rekordy, które będą renderować wszystkie oprócz id: 119. Kolejny LIMIT 3,3 zwróci id: 119 który nie Renderuj poprawnie, ponieważ jego rodzice nie są obecni.
Jedno rozwiązanie, które zastosowałem, to użycie dwóch zapytań:
- pierwszy zwraca tylko węzły główne. Można je sortować i to właśnie to zapytanie jest paginowane.
- jest wydawane drugie zapytanie, oparte na pierwszym, które zwraca wszystkie dzieci z paginowanych rodziców. Powinieneś być w stanie sortować dzieci według poziomu.
W moim przypadku mam Model Post (który ma_ancestry). Każdy post może mieć dowolny poziom odpowiedzi. Również obiekt post ma licznik odpowiedzi, który jest licznikiem pamięci podręcznej dla jego bezpośrednich dzieci.
W kontrolerze:
roots = @topic.posts.roots_only.paginate :page => params[:page]
@posts = Post.fetch_children_for_roots(@topic, roots)
W modelu Post:
named_scope :roots_only, :conditions => 'posts.ancestry is null'
def self.fetch_children_for_roots(postable, roots)
unless roots.blank?
condition = roots.select{|r|r.replies_count > 0}.collect{|r| "(ancestry like '#{r.id}%')"}.join(' or ')
unless condition.blank?
children = postable.posts.scoped(:from => 'posts FORCE INDEX (index_posts_on_ancestry)', :conditions => condition).all
roots.concat children
end
end
roots
end
Niektóre uwagi:
- MySQL przestanie używać indeksu kolumny ancestry, jeśli zostanie użytych wiele podobnych poleceń. Indeks siły zmusza mySQL do użycia indeksu i zapobiega pełnemu skanowaniu tabeli
- instrukcje LIKE są budowane tylko dla węzłów z bezpośrednimi potomkami, więc w kolumnie replies_count pojawiła się handy
- metoda klasy dodaje dzieci do roota, czyli kolekcji WillPaginate::
Wreszcie, można nimi zarządzać według Ciebie:
=will_paginate @posts
-Post.arrange_nodes(@posts).each do |post, replies|
=do stuff here
Kluczową metodą jest arrange_nodes , która jest mieszana z wtyczki ancestry i do twojego modelu. To w zasadzie pobiera posortowaną tablicę węzłów i zwraca posortowany i hierarchiczny Hash.
Doceniam, że ta metoda nie odnosi się bezpośrednio do twojego pytania, ale mam nadzieję, że ta sama metoda, z poprawkami, może być zastosowana w Twoim przypadku.
Jest prawdopodobnie bardziej elegancki sposób na to, ale ogólnie jestem zadowolony z rozwiązania(dopóki nie pojawi się lepsze).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-29 17:47:54