Pagination in Ruby On Rails using will_paginate plugin

31 10 2007


We do pagination in Rails by using its built in paginate method in our controller


def display_data
@display_data_pages, @display_data = paginate(:location_data,
:conditions => ["loc.updated_at < ?", params[:date]],
:joins => “as loc inner join location_address as locadd on loc.id = locadd.id”
:per_page => 10,
:order => “location_name”)
end

Often we would like to put this code inside our model mainly for two reasons:
1) Code Reuse, and
2) To keep the business logic where it belongs
But we couldn’t do that (since it is difficult to do) due to the paginate method and had to write the same code more than once in the controller and sometimes in more than one controller.
On top of that we have to put this chunk of code in our views only to show the pagination links
<div class="pagination">
<%= if @survdefault_pages.current.previous
link_to(”< Prev”, { :page => @survdefault_pages.current.previous })
end %>


<%= pagination_links(@survdefault_pages) %>

<%= if @survdefault_pages.current.next
link_to(”Next >”, { :page => @survdefault_pages.current.next})
end %>
</div>

We can put this code inside a partial but it is still a pain.

Moreover, Rails’ built in pagination will be out of Rails before it will reach version 2 which is not that far.

Update: Rails built in pagination is now removed but is still available as a plugin, ie, classic_pagination.

We have another option, use will_paginate plugin. The advantages of will_paginate plugin are:
1) Easy to use,
2) Less code in views to show pagination links, and
3) It can be used inside models

Follow these steps to use will_paginate plugin

1) Grab it, by going to the command prompt and change directory to the app root. Then run
ruby script/plugin install svn://errtheblog.com/svn/plugins/will_paginate
NOTE If the above code doesn’t installs the plugin in your vendor/plugins directory then you probably don’t have svn installed on your machine.

2) Now in our controller we can simply write

def display_data
@display_data = LocationData.paginate(:page => params[:page],
:conditions => ["loc.updated_at < ?", params[:date]],
:joins => “as loc inner join location_address as locadd on loc.id = locadd.id”, :per_page => 10,
:order => “location_name”)
end

:per_page and :page are required.
The best thing is, as mentioned above, we can move this code to the LocationData model that will help in keeping our controller clean and will also help in code reuse.
To do that, we can create a class method in our model like:

def self.display_location_data(update_date, page)
paginate(:page => page, :conditions => ["loc.updated_at < ?", update_date], :joins => “as loc inner join location_address as locadd on loc.id = locadd.id”,
:per_page => 10,
:order => “location_name”)
end

In our controller, the display_data method will now be replaced with just one line

def display_data
@display_data = LocationData.display_location_data(params[:date], params[:page])
end

In the view, the big chunk of code will be replaced by a single line to show our pagination links, like

<%= will_paginate @display_data %>

And we are done…

UPDATE: Formatting / Styling pagination links


Sign up and be a part of SPhred.com and don’t forget to invite your friends ;o)



Actions

Information

17 responses to “Pagination in Ruby On Rails using will_paginate plugin”

26 12 2007
Balachandran (07:08:27) :

Dear sir,
How to do the pagination using joining tables as well as joining tables.
For example:
I have 5 tables.
1st query joining with 3 tables and assigned one variable
2nd query joining with 3 tables and assigned one variable
3rd query joining with 3 tables and assigned one variable
Finally i was concatenate those three queries and assigned one variables.
so finally i want to do pagination. i dont know how to do??
Can u reply me.??
Regards
bala

26 12 2007
nasir (14:32:39) :

hi Bala
Before I answer your questions, I need to know why you want to do something like this:
“1st query joining with 3 tables and assigned one variable
2nd query joining with 3 tables and assigned one variable
3rd query joining with 3 tables and assigned one variable”

Why can’t you just get everything in one join query instead of three? OR Do you really need to show all that data on every page?

To me it looks more like a design problem rather than a pagination issue.

I would love to help but can you describe it in a bit more detail why you want to do something like this and the problem you are trying to solve.

Cheers

Nasir

27 12 2007
links for 2007-12-27 « Bloggitation (00:24:13) :

[...] Pagination in Ruby On Rails using will_paginate plugin (tags: ruby rails programming) [...]

15 04 2008
Paul Kenjora (20:53:55) :

How do I style the pagination tags with custom CSS?

I need to inject divs and spans into the generated html.

16 04 2008
Formatting/styling will_paginate « class Nasir < Jamal (09:17:31) :

[...] 16 04 2008 I received few requests in the past ( personally and recently a comment on my post for how to use will_paginate plugin ) about how to format pagination links while using will_paginate [...]

16 04 2008
nasir (09:20:17) :

Hi Paul,

I thought it required a new post, follow this link http://nasir.wordpress.com/2008/04/16/formattingstyling-will_paginate

2 05 2008
Shikha (04:19:23) :

How can we pass get parameters when user navigates to enother pages using will_paginate?

2 05 2008
nasir (04:53:00) :

You don’t have to do any thing special for that in

<%= will_paginate @obj_instance %>

just provide the link normally like so:

<%= link_to('A link', :controller => :jobs, :action => :index, :skill_type => 'ruby') %>

or if you are app is RESTful then

<%= link_to('A link', jobs_path(:skill_type => 'ruby')) %>

If you have a page at http://www.example.com/jobs that uses pagination and can be accessed at http://www.example.com/jobs?page=2, http://www.example.com/jobs?page=3, etc then your skill_type parameter will be added in the URL, for instance, http://www.example.com/jobs?page=2&skill_type=ruby That is, all your pagination urls will have an additional parameter of skill_type and its value attached to it.

20 05 2008
sijo (06:23:23) :

Hi
I have a search UI.And I use will_paginate to paginate result.My action
is
def search_sd_ticket
#@search_sd_ui_hash=params[:sd_ticket]
@search_sd_ticket_result=ServiceDeskTicket.record_paginate_sd(params[:sd_ticket],params[:page])

end

and in ServiceDeskTicket model

def self.record_paginate_sd(search_sd_ui_hash,page)
def self.record_paginate_sd(search_sd_ui_hash,page)
paginate(:page => page, :conditions => ["number LIKE ?",
"%#{sd_ticket_number}%"],
:per_page => 10,
:order => “number” ;)

end

My problem is the first page comes but when i click on the next page the
following error happens
You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]

The second time params[:sd_ticket] has no value..ow can I solve
this?Please help

Sijo

20 05 2008
nasir (08:44:13) :

Sijo

The problem is in the class method of your model here
:conditions => ["number LIKE ?", "%#{sd_ticket_number}%"]

if you change sd_ticket_number to search_sd_ui_hash then i think it should work fine because i cant see you getting a value for sd_ticket_number from anywhere though you are passing search_sd_ui_hash parameter to your class method in the model

22 05 2008
ganesh (10:52:08) :

Hi,
Is it possible to apply pagination for two tables

22 05 2008
ganesh (10:53:05) :

Hi,
Is it possible to apply pagination for two objects

Eg:

22 05 2008
Dave (21:39:27) :

I had trouble installing the plugin on Windows, this page helped though: http://github.com/mislav/will_paginate/wikis/installation

Just leaving the link for others to find.l

27 05 2008
nasir (05:57:39) :

Hi ganesh,

You can join the two tables to get the result set and then use the pagination.

27 05 2008
nasir (05:58:05) :

Thanx Dave

20 06 2008
Niksan (07:07:20) :

Hi Nasir!

I have used this pagination on one of the pages. I want to edit the styles for only the Previous or Next links. The current styles define a Link in a general way and have 2 styles ‘current’ and ‘disabled’ only for the two .

Is there a way to apply a separate css class to Previous and Next links?

Awaiting your reply.

Thanks in advance,
Nik

20 06 2008
nasir (12:29:37) :

Nik

Yes you can. In your view, instead of doing
will_paginate object
do this

will_paginate(object, :next_label => "<span class='class_name'>Next label</span>", :prev_label => "<span class='class_name'>Previous Label</span>" )

This will add css classes before your previous and next label.

Leave a comment

You can use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>