endless_pageless: An unobtrusive pageless pagination in Rails plugin
- At a glance
- This entry was written on April 11, 2007.
- The entry prior to this is entitled Widgetize your world.
- The entry following this is entitled Introducing IndyPaws.
- There are 2 comments on this post.
- This entry has been tagged as Recommended, Work, examples, javascript, plugins, rails.
- Archives are also available.
NOTE: Whoa, that’s an old entry here folks. Give me a little bit to get it squared back away (like switching it to will_paginate and making it so you can actually get to the code). Thanks to RubyFlow for the link, though. The plugin is now at github:
http://github.com/dummied/endless_pageless/tree/master
FINAL NOTE: Dude, don’t use this, follow the instrux at RailsCasts.
Whew, saved me from having to actually wrangle with that old code.
After tweaking and using the technique extensively in my current work project, I’ve taken the pageless technique I mentioned a while ago and rolled it into a small Rails plugin.
It’s my first Rails plugin, and it’s really not much at all (a little JS and a few text helpers), but you can install it via:
script/plugin install http://svn.movableparts.net/endless_pageless/trunk/endless_pageless
The plugin, right now, is pretty majorly tuned to my particular setup, so it requires the use of the paginating_find plugin. I’d like to decouple the two in the future, but I’m not sure when I’m going to get around to it. paginating_find can be installed via:
script/plugin install http://svn.cardboardrocket.com/paginating_find
The endless_pageless plugin includes basic RDoc documentation, a folder of example code (oddly, /example_code) and two javascript files: paginator.js (which does the actual pageless triggering) and a 1.5 version of prototype.js (your existing version of prototype.js will be backed up to prototype.bak on install).
Behind the scenes
A lot of the codebase for this plugin is significantly different than the package I put out there earlier: The JS is significantly smaller, the back button is hosed and there’s an extra helper method that you can use to get one filler.rjs template to do all the filling for you if you manage to get everything named properly.
The first two items — a smaller JS footprint and the hosed back button — are related. In practical use of my tweaked version of Unspace’s original JS, I discovered a bit of problem when you started using the technique on multiple pages: You end up with a shitload of cookies.
And that, in my case at least, eventually interfered with Rails session cookies.
The original JS set three cookies for each implementation, all related to supporting the use of the back button to return to a spot on the page. It’s a good and noble idea, but I had to pull it out for practical considerations (again, the sessions thing) … and I’m not that broken up about it.
First, I feel we’re worrying about an edge case here. Ninety-percent of the time, hitting the back button’s going to pull a cached version of the results anyway … and the other 10-percent of the time, folks will just scroll down until they find their content.
Secondly, three cookies per implementation just seems, well, unseemly, to me. For this to be a practical alternative to traditional pagination, I feel it needs to have a lighter footprint. Now it does.
In the RDoc, I briefly explain how to use the new stringify method to DRY up your views, but I figured I’d explain it a little bit more here.
Let’s say you’re wanting to endless paginate listing pages of Users, Jobs and Companies models.
Let’s also say you have partials called _user.rhtml, _job.rhtml and _company.rhtml that represent the data view that matches those models and to-be-filled divs id’d as users, jobs and companies, respectively.
Before I added stringify (and I added it specifically for this), you would have needed a different .rjs template to fill with all three models. Now you can have one that you call from all three controllers that looks like this:
page.insert_html :bottom, "#{stringify(@items).pluralize}", {:partial => "{stringify(@items)}", :collection => @items}
I also use stringify in the plugin itself to guess a name for the items you’re filling with in the loading message.
All stringy does is check the class of the first item, downcase the string and return the result. Then you can use all the associated methods, like .to_sym for instance, to bend that string into whatever shape you need to DRY up for filler views.
That’s all purely optional, though.
One other change is to the controller layout. Another discovery I made in the practical application of this has more to do with the way paginating_find works than anything else. When I started using stringify, I suddenly saw my log files littered with repeated queries for the same group of items.
It took me a while to realize that paginating_find does not actually load the results of your query, only the pages, until you call .each or .to_a. So, I needed to send actual items, and not pages, to stringify to get it to work properly. Which meant changing my controller setup to something more like this:
def pageless
if params[:page]
@pages = Post.find(:all, :page => {:size => 5, :current => params[:page].to_i})
@items = @pages.to_a
else
@pages = Post.find(:all, :page => {:size => 5, :current => 1})
@items = @pages.to_a
end
respond_to do |format|
format.html { render :layout => 'pageless' } # pageless.rhtml
format.js { render :action => 'filler', :layout => false } #filler.rjs
end
end
Wrapping up
This is my first Rails plugin, so please let me know if it doesn’t work for you, if it’s littered with bugs or if you’d like to see something changed.
Just drop a line to dummied@gmail.com with any of that stuff.
Comments
There are 2 comments on this post. Post yours →
Do you have a sample/demo for this? It sounds interesting but a visual would help lots of people decide if they really wanna try it out.
Btw, thanks for being a contributing member of the community.
~ mel
There’s a simple demo at:
http://dummied.org/pageless
Again, BIG caveat: this is old code and the svn repo’s not even up right now.
RubyFlow caught me with my pants down just a little bit. I’ll try to get everything cleaned up before noon (Eastern).
Post a comment