Formatting/styling will_paginate


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

So here it is:

When you add

<%= will_paginate @obj_instance %>

in your views to show your pagination links then it also creates an element (div) and wraps the whole thing under the class name pagination. The one with the current page will have the class name current.

Here is the html code generated by will_paginate


<div class="pagination">
<a href="/page_path?page=2">« Previous</a>
<a href="/page_path">1</a>
<a href="/page_path?page=2">2</a>
<span class="current">3</span>
<a href="/page_path?page=4">4</a>
<a href="/page_path?page=5">5</a>
<a href="/page_path?page=4">Next »</a>
</div>

Now, it is totally upto your imagination how you want to style it using CSS.

But, if due to some reason you don’t want to use the class pagination and add your own then do something like this


<%= will_paginate @obj_instance, :class => 'my_class' %>

Similarly, if you want to add an element id then

<%= will_paginate @obj_instance, :id => 'my_element' %>

Let’s say if you have done both like so:

<%= will_paginate @obj_instance, :id => 'my_element', :class => 'my_class' %>

then the new html generated by will_paginate will be

<div class="my_class" id="my_element">
<a href="/page_path?page=2">« Previous</a>
<a href="/page_path">1</a>
<a href="/page_path?page=2">2</a>
<span class="current">3</span>
<a href="/page_path?page=4">4</a>
<a href="/page_path?page=5">5</a>
<a href="/page_path?page=4">Next »</a>
</div>

Yes, it is that simple.

Pagination in Ruby On Rails using will_paginate plugin


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