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.

Author: map7, 2011-06-07

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ń:

  1. pierwszy zwraca tylko węzły główne. Można je sortować i to właśnie to zapytanie jest paginowane.
  2. 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).

 4
Author: Nazar,
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