will_paginate is the standard pagination plugin for many a Rails-2 site, and it's extremely flexible.
However it has one drawback: it will only show links - if there is more than one page.
This is mostly not a problem, if the links are all you show. But lets say you also use it to show the "Showing 26 to 50 of 342 matches" summary. Then lets say you want it to show "Showing 1 to 16 of 16 matches" - even when there's only a single page (for the sake of UI consistency). will_paginate does not provide an option for this.
There's talk of adding a :show_always => true option to will_paginate, but last I looked it hadn't been dragged into master...
So I wrote my own monkey-patch.
You'll need to put the following two snippets into config/intiializers/will_paginate.rb
The first thing you need to do, is make the "summary" sections public, so they are available to the renderer (which is the thing that generates all the page-links for you). Here's mine (both scavenged and adapted from the web many years ago):
module WillPaginate
class LinkRenderer
# generates eg: "1 - 15 of 15" or "26 - 50 of 342"
def matches_summary
if 0 == @collection.total_entries
# because "0 - 0 of 0" is a bit much
summary_text = "0 Matches"
elsif 1 == @collection.total_entries
summary_text = "1 Match"
else
summary_text = "%d - %d of %d" % [ @collection.offset + 1,
@collection.offset + @collection.length, @collection.total_entries ]
end
page_span(1, summary_text, :class => "summary")
end
# generates "Page 4 of 62" or "Page 1 of 1"
def pages_summary
if 0 == @collection.total_pages
# because "Page 0 of 0" is a bit much
summary_text = "0 Pages"
elsif 1 == @collection.total_pages
summary_text = "1 Page"
else
summary_text = "Page %d of %d" % [ current_page, @collection.total_pages ]
end
page_span(1, summary_text, :class => "summary")
end
end # LinkRenderer class
end # WillPaginate module
And this chunk is what makes will_paginate:
- Accept the ":show-always => true" option
- If the above is passed, and there are no page-links... displays the summaries
module WillPaginate
module ViewHelpers
# This lets us still use any will_paginate passed-in renderers if we want
# adapted by code in original will_paginate
def fetch_renderer(renderer)
case renderer
when String
renderer.to_s.constantize.new
when Class
renderer.new
else
renderer
end
end
# don't lose the old will_paginate
alias :old_will_paginate :will_paginate
# overload actual will_paginate call to allow us to choose to show the
# "number of matches" box even if there is only one page
def will_paginate(collection, options = {})
# strip out the show_always option
show_always = options.delete(:show_always)
# do standard pagination
html = old_will_paginate(collection,options)
# if we didn't get anything, but we have "show always" = true
if html.nil? && show_always
# set up the renderer (stolen directly from standard will_paginate)
options[:container] = true
renderer = fetch_renderer(options[:renderer])
renderer.prepare collection, options, self
# produce the "matches" boxes through the renderer
links = [renderer.matches_summary, renderer.pages_summary]
# generate the html for the pagination links -
# default the html-attributes to the plain pagination class
html = content_tag(:div, links, (renderer.html_attributes||{}).merge(:class => 'pagination'))
end
html
end
end
end
Then you can call it with this:
<%= will_paginate @things, :show_always => true %>