Go to blue arrow
back to Tech Blog
Udvikling
Tiago Franco

10. august 2026

Min Read

Pagy, Kaminari, will_paginate: Hvorfor vælge Pagy?

Mørkt UI-tabel med stjernenavne og radier samt Side 1 af 4-kontroller til paginering med Pagy i Rails.

Det korte svar: Ifølge den paginerings-benchmark, som Pagys forfatter har offentliggjort, er Pagy med stor afstand den letteste af de tre mest udbredte Ruby on Rails-gems. Ved rendering af den samme navigation over de samme records allokerer den 184 objekter hvor will_paginate allokerer omkring 3.200 og Kaminari omkring 6.400. I en applikation med tusindvis af samtidige brugere betyder den forskel noget for din hukommelsesgrænse pr. instans, hvilket direkte påvirker antallet af instanser, du skal betale for.

Lad os først få én ting på plads, da meget af det materiale, der stadig florerer, er forældet: Pagy er ikke længere den lille udfordrer. Den udkom første gang i februar 2018 og er i dag et modent og meget udbredt bibliotek. Det, der har ændret sig, er API'et. Pagy 43 var en total rekonstruktion fra bunden, så de fleste vejledninger, du finder (inklusive vores egne indtil nu), viser kald, der ikke længere eksisterer. Jeg har bygget Rails-apps siden version 0.8 og har brugt alle tre gems til paginering i produktion; denne artikel er skrevet om til den aktuelle version.

blue arrow to the left
Imaginary Cloud logo

Hvor de tre gems reelt står i 2026

Inden vi ser på benchmarken, skal vi se på vedligeholdelsen, for "hvilken er hurtigst" betyder mindre end "hvilken bliver der stadig taget hånd om", når du skal binde en kodebase til den i årevis.

GemNuværende versionSeneste udgivelseVedligeholdelsessignal
Pagy43.x2026Aktivt udviklet; hyppige udgivelser; fuldt redesign i v43
Kaminari1.2.2December 2021Stadig den absolut mest installerede, men ingen udgivelser i over et år
will_paginate4.0.1Juni 2024Officielt i vedligeholdelsestilstand: ingen nye funktioner, og README henviser selv brugere til alternativer

Et par ting kan udledes af den tabel.

will_paginate er ikke død, men dens egen vedligeholder har sat en stopper for videre udvikling. Den fik understøttelse af Rails 7 i 4.0-udgivelsen og modtog en rettelse i 2024, så påstanden om, at "sidste commit var i 2017", som man ser i ældre indlæg (inklusive vores egne), er ganske enkelt forkert. Den korrekte grund til at undgå den i nye projekter er ikke manglende vedligeholdelse. Det er, at vedligeholderen eksplicit har sat den i vedligeholdelsestilstand og er holdt op med at tilføje funktioner. Et fair grundlag for en beslutning; men et forkert grundlag, hvis du henviser til en commit-dato fra 2017.

Kaminari er den etablerede spiller, og det betyder stadig noget. Den har den største installerede base af de tre med stor margin, en omfattende dokumentation, view-skabeloner, som du kan generere og tilpasse, samt konfiguration pr. model. Men dens seneste udgivelse var i december 2021. Den virker, den er stabil, og på et admin-panel med lav trafik vil ingen af de performance-diskussioner, der følger herunder, nogensinde være synlige for dig. Momentum ligger dog tydeligvis et andet sted.

Pagy er der, hvor den aktive udviklingsenergi befinder sig. Udover rå hastighed leverer den nu adskillige paginerings- teknikker i én gem (offset, countless, keyset, keynav, calendar og search), plus rendering på server- eller klientsiden samt interaktive udviklerværktøjer. Den bredde, og ikke kun hukommelsesforbruget, er en stor del af grunden til, at folk vælger den nu.

blue arrow to the left
Imaginary Cloud logo

Rails' biblioteksboom, og hvorfor nye tilføjelser er sjældne

Antallet af nye RubyGems, der blev udgivet hvert år, voksede gennem starten af 2010'erne, toppede omkring 2015 og har været faldende siden. Det betyder ikke, at der ikke er noget nyt, der er værd at give opmærksomhed. Det betyder, at de virkelig nyttige nyheder er sjældnere nu og lettere at overse. Pagy var en af dem i 2018; pointen med en opdatering som denne er, at "sjælden og let at overse" også beskriver de ændringer i et godt bibliotek, når først fællesskabet er holdt op med at skrive om det.

Nye RubyGems udgivet pr. år

2010 til 2026

Bekræftet Estimeret
~4k
~8k
~14k
~22k
27k
~21k
~17k
~13k
~11k
~10k
~9k
~9k
~8k
~8k
~9k
~9k
~9k
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026

Bekræftede tal: 2014 (~27.000) og 2018 (~10.600 / ~29 pr. dag), fra Infinums RubyGems-analyser.

blue arrow to the left
Imaginary Cloud logo

Hvad er Pagy?

Hvis du har arbejdet med Rails før, har du sikkert brugt will_paginate eller Kaminari til at paginere indekssider i en applikation. Paginering er arbejdet med at opdele en lang liste af poster i nummererede sider og rendere links imellem dem. Hvis du er ny i Rails, vil du ret hurtigt få brug for en løsning til paginering.

Pagy er et pagineringsbibliotek bygget med ydeevne som højeste prioritet, uden at det er besværligt at bruge i nye eller eksisterende applikationer. Det er framework-agnostisk: Det fungerer med Rails såvel som med lettere Ruby-frameworks som Sinatra og Padrino, og det paginerer både Active Record-relationer samt almindelige arrays og andre samlinger.

Det var rimeligt at være skeptisk over for endnu en paginerings-gem tilbage i 2018. Fragmentering er ikke godt for open source, og nogle af de forbedringer, Pagy bragte med sig, blev oprindeligt foreslået til Kaminari og afvist med den begrundelse, at de ville kræve væsentlige ændringer af selve kernen i det gem. Den afvisning er halvdelen af grunden til, at Pagy eksisterer. Otte år senere er skepsissen for det meste forsvundet: Antallet af downloads og stjerner placerer Pagy solidt blandt de mest populære valg frem for at være et nicheprodukt.

blue arrow to the left
Imaginary Cloud logo

Hvorfor pagineringshukommelse betyder noget i en Rails-app

Tænk på hver gem på en request-sti som bagage. Du bærer rundt på den på hver tur, uanset om du åbner den eller ej, og paginering er den taske, der følger med på næsten hver eneste listeside i dit produkt. En tung taske er ikke et problem på én tur. Det er et problem, når du foretager ti tusinde af dem i timen.

Tallene herunder stammer fra den benchmark-suite, som er udgivet af forfatteren til Pagy, der renderer den samme Bootstrap-paginering over de samme records med hver gem efter tur.

Hvad benchmarken måler, og hvad den ikke gør

Suiten registrerer to ting pr. gem: den hukommelse, der allokeres til at udføre arbejdet, og antallet af Ruby-objekter, der allokeres. Den måler ikke databaseforespørgslen bag siden, som er den samme, uanset hvilken gem du bruger. Den måler heller ikke slutbrugerens sideindlæsningstid, som domineres af forespørgslen, viewet og netværket. Og da den er udgivet af forfatteren til en af de tre gems, bør den læses som en direkte sammenligning af paginerings-overhead snarere end som et uafhængigt forsøg.

To ærlige bemærkninger til tallene herunder. For det første benchmarker den publicerede suite stadig legacy-versionerne (Pagy v3, will_paginate 3.1.7, Kaminari 1.1.1), så betragt dem som overheaden for hver gems klassiske implementering. For det andet hævder Pagys nuværende v43 yderligere forbedringer i forhold til sin egen v3-baseline, så hvis noget, er den moderne forskel større, ikke mindre. Tallene er overheaden og intet andet.

Tallene

Gem (testet version)Allokerede objekterSamlet allokeret hukommelseHukommelsesvækst, 2 til 20 sider
Pagy (v3.0.0)184~19 KBFlad (ingen målbar stigning)
will_paginate (3.1.7)~3.198~341 KB~2x
Kaminari (1.1.1)~6.445~704 KB~4x

Objektallokering er der, hvor forskellen er mest markant. Kaminari opretter cirka 6.400 objekter for at rendere navigationen; will_paginate omkring 3.200. Begge er for tunge til opgaven. Pagy gør det med 184.

Vækstkolonnen betyder lige så meget som totalerne. Når du udvider pagineringslinjen fra 2 til 20 links, forbliver Pagys hukommelsesforbrug stort set uændret, mens will_paginate omtrent fordobles, og Kaminari omtrent firedobles. På en travl listeside med en bred pagineringslinje betales den pris ved hver eneste forespørgsel.

Der er også en historie om kodestørrelse bag historien om hukommelse. For at producere det identiske output er Pagy på omkring 4 filer og ~140 linjer; Kaminari spænder over ~36 filer, will_paginate ~23. Mindre kode til at udføre det samme arbejde betyder normalt færre allokeringer og mindre at forholde sig til, og her viser det sig direkte i profilen.

Allokerede objekter til at generere paginering

Samme navigation, samme poster. Lavere er bedre.

Pagy
184
will_paginate
~3.198
Kaminari
~6.445

Ruby-objekter allokeret til at generere det samme pagineringsresultat. Kilde: Pagy-forfatterens benchmark-test (ddnexus/pagination-comparison), ældre gem-versioner. Pagy 43 hævder yderligere forbedringer i forhold til v3-udgangspunktet vist her.

Så hvad får du ud af det? Ikke hastighed, primært

Hvert allokeret objekt er hukommelse, der optages og derefter frigives af garbage collection (det baggrundsarbejde, Ruby udfører for at frigøre hukommelse, der ikke længere er i brug), og det hele sker på en sti, der kører på de fleste listesider i produktet. At reducere allokering pr. forespørgsel med en størrelsesorden gør ikke en sideindlæsning mærkbart hurtigere. Det øger antallet af samtidige forespørgsler, en given instans kan håndtere, før du skal tilføje en ny. På en infrastrukturregning, der er baseret på antallet af instanser, er det her, besparelsen ligger, og den migrering, der muliggør det, måles i timer frem for i sprints.

Vi ser dette mønster i vores eget leveringsarbejde. Da vi genopbyggede FlippedNormals, en markedsplads for computergrafik, kunne den gamle WordPress-platform ikke længere følge med trafikken, så vi migrerede den til en tilpasset Ruby on Rails-applikation og flyttede den til AWS for at få en mere skalerbar infrastruktur. Hele migreringen tog to måneder og løftede trafikken med 4 % efter relanceringen. Det er et nyttigt eksempel til denne diskussion netop på grund af dens form: et katalog med mere end 28.000 produkter betyder, at liste-, søge- og browsesider er på den kritiske sti, som rammes ved næsten hver eneste forespørgsel. Det er præcis de sider, hvor en paginerings-gems omkostning pr. forespørgsel ganges med din trafik, og hvor det valg, der blev truffet tidligt, i det stille fastsætter ressourceloftet senere.

blue arrow to the left
Imaginary Cloud logo

Derfor bruger Pagy mindre hukommelse

  • Den udfører sine beregninger på heltal frem for Ruby-objekter, så omkostningerne vokser ikke i takt med samlingens størrelse.
  • Kernen er lille, blot et par dusin linjer, og alle moduler og metoder er en del af det offentlige API, som kan tilsidesættes direkte uden brug af monkey-patching eller underklasser.
  • Den genererer sin egen HTML, URL'er, flertalsformer og interpolation, så den holder sig helt ude af dine applikationsmodeller.
  • Den bruger specialbygget kode frem for generiske hjælpere, og i v43 indlæses kun de metoder, du rent faktisk kalder, så ubrugte funktioner optager ingen hukommelse.

Der er en stor sidegevinst ved alt dette: Koden er oprigtigt let at læse, hvilket er grunden til, at forfatteren har været i stand til at profilere den linje for linje.

blue arrow to the left
Imaginary Cloud logo

Sådan finder du de gems, der ligger på dine hot paths

Paginerings-gems er ét eksempel på et bredere mønster, og det er netop dette mønster, vi leder efter, når vi gennemgår en Rails-stack. Vi kalder det en gem resource audit. Tre trin.

1. Lav en oversigt over, hvad der kører ved hver forespørgsel. Ikke hele din Gemfile, kun de gems, der bliver kaldt på de sider, hvor du rent faktisk har trafik: index- og listesider, søgeresultater og dashboards. Paginering, serialisering, autorisations-tjek og view-helpers ender typisk på denne liste. En gem, der kun bruges én gang om dagen i et baggrundsjob, er ikke værd at måle på.

2. Mål allokering, ikke svartid. Antallet af objekt-allokeringer pr. forespørgsel er det tal, der bedst forudsiger, hvordan en applikation opfører sig under belastning, og det er stabilt nok til at sammenligne to forskellige implementeringer. memory_profiler og benchmark-ips giver dig både allokering og tidsforbrug for en enkelt handling. Forskellen mellem to gems til den samme handling er som regel tydelig allerede ved første kørsel.

3. Modeller resultatet i instanser, ikke megabytes. En besparelse bliver først et stærkt argument, når den udtrykkes som råderum: hvor mange flere samtidige forespørgsler en instans kan håndtere, og dermed hvor mange færre instanser den samme mængde trafik kræver. Det er det tal, en teknisk beslutningstager kan handle ud fra, og det, der retfærdiggør indsatsen ved en migrering.

De fleste Rails-applikationer slæber rundt på to eller tre af disse "tunge" gems. Paginering er den, vi oftest støder på, fordi den vælges tidligt, aldrig bliver revurderet, og ligger præcis på de sider, der får mest trafik.

blue arrow to the left
Imaginary Cloud logo

Kom godt i gang med Pagy 43 (nuværende API)

Det er her, ældre guides vil lede dig på vildspor: Pagy::Backend / Pagy::Frontend includes, items: nøgleordet og pagy_nav hjælperen er alle fra før v43. Her er den aktuelle opsætning, som følger den officielle quick-start guide.

1. Tilføj gem'en, låst til minor-versionen (v43 bruger et spring i versionsnummeret, så en låsning til minor-versionen beskytter dig mod breaking changes):

# Gemfile
gem 'pagy', '~> 43.6'

Pagy 43 kræver Ruby 3.3 eller nyere.

2. Inkludér det enkelte entry-point modul i din application controller:

# app/controllers/application_controller.rb
include Pagy::Method

Den ene include erstatter det gamle modul med to dele (Backend plus Frontend) opsætning. Metoder indlæses automatisk, når de bruges.

3. Paginer i controller-handlingen. Vælg en paginator: :offset er den klassiske metode, :keyset er den hurtigste til store, sorterede samlinger:

# Offset pagination (the familiar page-number behaviour)
@pagy, @records = pagy(:offset, Product.all, limit: 20)

# Keyset pagination (fastest for large, ordered datasets)
@pagy, @records = pagy(:keyset, Product.order(:id).all, limit: 20)

Bemærk limit:, som erstattede det gamle items: nøgleord.

4. Gengiv navigationen i viewet. Hjælpefunktionerne er nu metoder på @pagy objektet:

<%# Server-side navigation bar %>
<%== @pagy.series_nav %>

<%# Or a client-side, responsive variant, styled for Bootstrap or Bulma %>
<%== @pagy.series_nav_js(:bootstrap) %>
<%== @pagy.input_nav_js(:bulma) %>

<%# A "showing 476-500 of 1000" style summary %>
<%== @pagy.info_tag %>

Det var hele hurtigstarten. Hvis du vil tilpasse din app's tema interaktivt eller stille Pagys indbyggede AI et spørgsmål direkte fra din egen app, aktiverer en enkelt linje i dit layout head udviklerværktøjerne:

<%== Pagy.dev_tools %>
blue arrow to the left
Imaginary Cloud logo

Migrering fra will_paginate eller Kaminari til Pagy

Flytningen foregår i controlleren og viewet (filen, der håndterer forespørgslen, og skabelonen, der renderer siden). Den officielle migreringsvejledning opdeler det i nogle få mekaniske trin, og i praksis svarer det næsten én-til-én.

Controller. Gamle kald kan oversættes direkte:

# will_paginate
# @records = Product.some_scope.paginate(page: params[:page], per_page: 15)

# Kaminari
# @records = Product.some_scope.page(params[:page]).per(15)

# Pagy
@pagy, @records = pagy(:offset, Product.some_scope, limit: 15)

View. Udskift hjælperen:

<%# will_paginate: <%= will_paginate @records %> %>
<%# Kaminari:      <%= paginate @records %> %>

<%== @pagy.series_nav %>

Global konfiguration. Søg i din kodebase efter den gamle gems klassenavn (WillPaginate, Kaminari) og fjern dens initialiseringsfiler og eventuel monkey-patching. En global per_page bliver til Pagy::OPTIONS[:limit] i en Pagy-initialiseringsfil, eller en limit:pr. kald. Hvis du har benyttet dig af Kaminaris .page scope inde i model-metoder, fjern den der og anvend paginatoren i controlleren i stedet.

Kør derefter dine tests, eller klik dig igennem siderne. Eventuel tilbageværende legacy-kode vil fejle, så fjern den og prøv igen, indtil appen renderes fejlfrit. Hvis du brugte Bootstrap- eller Bulma-pagineringsstile, fungerer den eksisterende CSS med Pagys series_nav hjælpere.

Fordele og ulemper, kort fortalt

Pagy er ikke en direkte erstatning: Du kan ikke bare udskifte gemmen og lade din kode være urørt. Hjælpernavnene er anderledes, så hver pagineret visning skal gennemgås, og samlingen dekoreres ikke længere med sidemetoder på samme måde, som Kaminari dekorerer en Active Record-relation. Enhver kode, der kalder disse metoder, skal ændres. Pagys hjælpere returnerer rå HTML-strenge, hvilket er præcis det, der holder dem hurtige.

I en applikation med en håndfuld indekssider er dette klaret på en eftermiddag. Hvis du har halvtreds, bør du planlægge det som en afgrænset opgave og behandle den, som du ville enhver ændring af kode, der kører ved hver forespørgsel: bag en review-proces og med tjek af siderne. Hvis du hellere vil uddelegere det, er dette den type afgrænsede arbejde, som vores Ruby on Rails-udviklingstjenester dækker.

blue arrow to the left
Imaginary Cloud logo

Hvornår Kaminari (eller will_paginate) stadig er det rigtige valg

En ærlig anbefaling kræver også et "hvornår man ikke bør".

Bliv ved Kaminari, når applikationen allerede er bygget tæt op omkring det (du benytter dig af de genererede visningsskabeloner og konfiguration pr. model), eller når de paginerede sider har så lav trafik, at forskellen i hukommelsesforbrug aldrig vil kunne ses på din regning. Kaminari er modent, veldokumenteret og stadig det mest installerede af de tre. Argumentet for Pagy er et ressource- argument, og det er stærkest, hvor paginering er en kritisk del af systemet.

will_paginate er sværere at anbefale til nye projekter, da vedligeholderen har lukket for nye funktioner. Men hvis du har en stabil app, der allerede bruger det, og du ikke oplever problemer med ydeevnen, så er "i vedligeholdelsestilstand" ikke det samme som "ødelagt". Der er ingen grund til at skifte bare for skiftets skyld.

Ressourceargumentet for Pagy er reelt, men det er et argument, ikke et bud. Tilpas det til din trafik.

Hvad det koster at vælge gems uden at måle dem

Jeg startede med will_paginate, fordi det var det bedste værktøj på det tidspunkt. Jeg skiftede til Kaminari et par måneder efter lanceringen, og blev der, indtil et par uger efter Pagy dukkede op.

Det, der overraskede mig senere, var, at jeg var skiftet fra will_paginate til Kaminari uden overhovedet at tage højde for ydeevnen, og ifølge den offentliggjorte benchmark er Kaminari den tungeste af de to. Ingen benchmark fra min side. Bare rutine.

Det rejser et relevant spørgsmål om resten af stacken: Hvor mange gems slæber vi rundt på, som i det stille skader de applikationer, vi designer og leverer, fordi de er valgt på samme måde og aldrig er blevet målt siden? Det er spørgsmålet bag ovenstående audit, og i vores eget leveringsarbejde er det nu et fast punkt frem for en eftertanke, for omkostningen ved at stille spørgsmålet for sent er en infrastrukturregning, som ingen kan forklare. Logikken rækker langt ud over paginering og langt ud over Rails. Det framework, du vælger, sætter bunden. De biblioteker, du bygger ovenpå, sætter loftet.

Som en ansvarsfraskrivelse: Ydeevnetallene ovenfor stammer fra den benchmark-suite, som Pagys forfatter har offentliggjort (ddnexus/pagination-comparison), kørt på legacy-versionerne af hver gem.

Ofte stillede spørgsmål

Bruger folk stadig Pagy i 2026?

Ja, i stor stil. Det er gået fra at være en nykommer til at være et af de foretrukne valg til paginering i Rails, med titusindvis af downloads, tusindvis af stjerner på GitHub og regelmæssige udgivelser gennem 2026. Den aktive udvikling på dette område sker hos Pagy; Kaminari har den største installerede base, men har ikke udgivet en opdatering siden 2021.

Er Pagy hurtigere end Kaminari?

Ifølge forfatterens benchmark, ja, og med en stor margin hvad angår ressourceforbrug: Pagy allokerer omkring 184 objekter mod Kaminaris ca. 6.400, og bruger markant mindre hukommelse i alt. Den synlige forskel for brugeren ved en enkelt sideindlæsning er lille. Forskellen viser sig i, hvor mange samtidige forespørgsler en instans kan håndtere.

Hvordan migrerer jeg fra will_paginate eller Kaminari til Pagy?

Tilføj gem 'pagy', '~> 43.6', tilføj include Pagy::Method til din ApplicationController, erstat hvert .paginate(...) / .page(...).per(...) kald med @pagy, @records = pagy(:offset, scope, limit: N), og erstat view-helperen med <%== @pagy.series_nav %>Det er ikke en direkte udskiftning, og hver pagineret visning skal besøges, men ændringen er afgrænset og let at rulle tilbage.

Fungerer Pagy godt med store datasæt?

Ja. Beregningerne kører på heltal frem for Ruby-objekter, så omkostningerne vokser ikke med samlingens størrelse. For meget store, sorterede tabeller kan Pagys :keyset paginator helt undgå den dyreOFFSET -scanning. Den begrænsning, du til sidst rammer, er database-tællingen, ikke paginerings-gem'en, og det gælder for alle tre.

Hvilke frameworks og ORM'er understøtter Pagy?

Pagy er framework-agnostisk. Det fungerer med Rails og lettere frameworks som Sinatra og Padrino, og det paginerer Active Record-relationer såvel som almindelige arrays og andre samlinger. En ORM (object-relational mapper) er det lag, der omdanner databaserækker til objekter; Active Record er den, der er indbygget i Rails, og Pagy arbejder sammen med den frem for at koble sig direkte på dine modeller.

Hvad er ændret i Pagy 43?

Det var et komplet redesign. Opsætningen blev reduceret til en enkelt include Pagy::Method, konfigurationen blev skåret drastisk ned, og hjælpefunktionerne blev flyttet over på @pagy -objektet (@pagy.series_nav i stedet for den gamle pagy_nav(@pagy)). Det tilføjede også nye paginatorer (countish, keyset, keynav, calendar og search), rendering på klientsiden og interaktive udviklerværktøjer. Hvis du følger en ældre vejledning, skal du forvente, at metodenavnene er anderledes.

Hos Imaginary Cloud arbejder vi med en bred teknologistak, herunder Ruby on Rails. Hvis paginering er en kritisk del af din applikation, eller hvis du har mistanke om, at andre gems koster dig mere, end de burde, kan vi foretage den ovenfor beskrevne gem-ressourceaudit af din stak og fortælle dig, hvor ressourceforbruget reelt ligger. Kontakt os så kigger vi på det sammen.

UX-auditreklame, der viser fordele ved forbedret brugeroplevelse og engagement, med 3D-appgrafik.
Tiago Franco
Tiago Franco

CEO hos Imaginary Cloud og medforfatter til bogen Product Design Process. Jeg nyder mad, vin og Krav Maga (ikke nødvendigvis i den rækkefølge).

LinkedIn

Read more posts by this author

People who read this post, also found these interesting:

Dropdown caret icon