"Rails" Rankinis puslapiavimas (Pagination)

Posted by Mindaugas Kurlavičius Tue, 04 Sep 2007 19:32:00 GMT

Beveik kievienoje tinklo aplikacijoje yra reikalingas įrašų puslapiavimas. Kas tai yra, labai lengva suprasti apsilankius Google puslapyje. Ten visi paieškos rezultatai suskirstyti po 10 ir pateikiami atskiruose puslapiuose, į kuriuos nuorodos yra tvarkingai sudėliotos rezultatų apačioje.

Programiniame lygmenyje puslapiavimo algoritmas nėra labai sudėtingas, aplikacijai reikalingi tik du parametrai - įrašų skaičius vienam puslapiui (:limit), ir norimas puslapis (:page). Su šiais parametrais galime apskaičiuoti trečią parametrą - (:offset) pagal formulę offset = limit * (page - 1) ir formuoti efektyvias SQL užklausas kiekvienos užklausos metu iš DB pasiimdami tik reikalingą kiekį užrašų einamajam puslapiui. Paprasta, tačiau puslapiavimas vis dėl to yra nemenkas galvos skausmas programuotojams, o "Rails" bendruomenėje ima vyrauti nuomonė, jog pačio paprasčiausio "Rails" puslapiavimo geriau išvis nenaudoti : Things you shoudnt be doing in Rails.

Dokumentacijoje nurodytas metodas:

@person_pages, @people = paginate(
  :people, 
  :order => 'last_name, first_name'
)
atrodo labai patraukliai, tačiau praktikoje iš jo gali būti per mažai naudos. Jo trūkumas yra tas, kad negalima perduoti einamojo puslapio parametro, t.y. jis naudoja params[:page], taigi tokio modelio puslapyje, kur einamasis puslapis visada turi būti fone, nesvarbu, kokį kitokį veiksmą atlikome, prie kiekvienos nuorodos turime "prikabinti" params[:page]. Be, to tradicinis pagalbinis metodas "pagination_links" retai tinka praktiškai.

Patogus būdas (padedantis išvengti galvos skausmo) realizuoti puslapiavimą , tai pasidaryti rankomis pagalbinį metodą (kontrolerio arba bibliotekos) naudojantį žemesnio lygio puslapiavimo metodus.

def my_pagination(user, limit, page)
  @total = Record.count(:conditions => {:user_id => user.id})
  @records = Record.find(
    :all, 
    :conditions =>  {:user_id => user.id },
    :order      =>  'created_at DESC',
    :limit      =>  limit,
    :offset     =>  limit.to_i * (page.to_i - 1)
  )
  @record_pages = Paginator.new(self, @total, limit, page)
end

Tokį metodą naudojant kontrolerio veiksmuose (action), gaunami trys kintamieji iš kurių vėliau nesunku pasidaryti nuorodas į puslapius.

Taip pat, patogu yra params[:page] parametrą "prikabinti" tik prie nuorodų į įrašų puslapius, ir gavus aplikacijoje išsaugoti arba sesijos kintamajame arba kokiuose nors vartotojo nustatymuose, o užklausose, kuriose params[:page] nėra, naudoti išsaugotą parametrą.

Tags , , ,  | no comments | no trackbacks