While I was developing Motionspire, I needed to implement a pagination system for the video content. I looked through the existing plugins, but found that I really desired something extremely simple and custom to work within my search controller. With only a few lines of code, I created a very basic system for managing pagination that can be ported to other sites with ease.
The Search Controller
The Motionspire search controller uses one function and view for returning any content, whether it’s filtered or not, so the pagination only required one copy of the code to be implemented. I keep a session variable for maintaining the user’s preference for items per page, and if that parameter has been sent to the search function I set the session variable :
if params[:itemsPerPage] then session[:itemsPerPage] = params[:itemsPerPage] end
When I run though the search function, I see if a page parameter has been passed:
if params[:page] then @page = params[:page].to_i else @page = 1 end
After I retrieve the articles pertaining to the search parameters (in this case the results are stored into an array called @videos), I check the :itemsPerPage preference and find the last possible page:
if session[:itemsPerPage] then @per = session[:itemsPerPage].to_i else @per = 24 end
@lastpage = @videos.length/(@per) + 1
if @videos.length%(@per) == 0
@lastpage = @lastpage - 1
end
I have a default itemsPerPage value of 24 hardcoded, and you can change this for your search.
From here, we simply return the search results for that page, using the current page and the items per page preference:
@videos = @videos[((@page-1)*@per),@per]
For search queries within a large data set, I would recommend using these parameters with the sql query with the ‘ORDER BY’ and ‘LIMIT’ in order to avoid returning extremely large results unnecessarily.
The Helper
First, I created a short helper function that finds the min and max pages, ensuring we don’t show a negative page or a page that doesn’t exist:
def minmaxpage(current,total,option)
min = current - 2
if min < 1
min = 1
max = 1 + 4
if max > total then max = total end
end
max = min + 4
if max > total
max = total
min = max - 4
while min < 1
min = min + 1
end
end
if option == 'min' then return min else return max end
end
The View
For the content from the view, we use the @videos array to present the content for the page. The only custom coding necessary is in the links for the pages. For this site, I provide a first and last page link, along with 2 pages on either side of the current page. You can manipulate this code how you want, but the basic idea will remain the same.
First we grab the min and max page from the helper:
<% min = minmaxpage(@page, @lastpage, 'min') %>
<% max = minmaxpage(@page, @lastpage, 'max') %>
For the code for the page links, we simply check to see if the min page is within two of the current:
<% if min < @page %>
<%= link_to( "Prev",
:action => "search",
:page => (@page - 1) ) %>
<% end %>
<% if min > 1 %>
<%= link_to( "1",
:action => "search",
:page => 1 ) %>
<% end %>
<% x = min %>
Then we loop through the remaining pages, ensuring we don’t go over the max, and make the current page simple text instead of a link:
<% while x <= max %>
<% if x.to_i == @page.to_i %>
<span class="current"><%= x %></span>
<% else %>
<%= link_to( x.to_s,
:action => "search",
:page => x ) %>
<% end %>
<% x = x+1 %>
<% end %>
<% if max < @lastpage %>
<%= link_to( @lastpage.to_s,
:action => "search",
:page => @lastpage ) %>
<% end %>
<% if max > @page %>
<%= link_to( "Next",
:action => "search",
:page => (@page + 1) ) %>
<% end %>
The code may look a little long, but the implementation took very little time. I know exactly what the code is doing and it is very easy to expand this for different situations and code.
There are a lot of solutions for pagination of content, but I found that this simple implementation helped me avoid using plugins and save time. Let me know if you guys have any questions or comparable solutions.