Paged Scopes, Part II: Routing and Controller Methods
Last week I described the basics of my Paged Scopes rubygem for ActiveRecord. In this article I’ll describe some routing and controller methods that make Paged Scope pagination very easy to use in your Rails controllers.
(It should be noted that the use of these methods is optional. If you don’t like them, you don’t have to use them! Design your routes and paginate your collections in your controllers however you see fit.)
Page Routing
The most common way to represent a paginated collection in an URL is to tack on the page number as a query parameter: http://www.example.com/articles?page=3, for example.
I’m not a fan of this approach at all. For starters, it’s a bit ugly. More importantly, it won’t work with standard Rails page caching, which ignores query parameters.
I prefer to think of pagination as just another scoping of the collection. Just as we have paths like /users/9/articles, I prefer a paged collection to have paths like /pages/2/articles (or /users/9/pages/2/articles, for that matter).
To this end, the Paged Scopes gem adds a :paged option to the Rails resources mapper. We’ll use this option to define the routes for our articles:
ActionController::Routing::Routes.draw do |map| map.resources :articles, :paged => true end
Checking our routes using rake routes:
articles GET /articles(.:format) {:controller=>"articles", :action=>"index"}
POST /articles(.:format) {:controller=>"articles", :action=>"create"}
new_article GET /articles/new(.:format) {:controller=>"articles", :action=>"new"}
edit_article GET /articles/:id/edit(.:format) {:controller=>"articles", :action=>"edit"}
article GET /articles/:id(.:format) {:controller=>"articles", :action=>"show"}
PUT /articles/:id(.:format) {:controller=>"articles", :action=>"update"}
DELETE /articles/:id(.:format) {:controller=>"articles", :action=>"destroy"}
page_articles GET /pages/:page_id/articles(.:format) {:controller=>"articles", :action=>"index"}Just your standard set of resource routes, with one extra – the paged articles index route, last in the list. Specifying the :paged option in the mapping yields this extra route for use in our index actions. (Everything else remains the same.)
Want a bit more flexibility? We can pass :as or :name options to the paged option if needed:
map.resources :articles, :paged => { :as => :pagina } map.resources :users, :paged => { :name => :group }
Which would produce these routes:
page_articles GET /pagina/:page_id/articles(.:format) {:controller=>"articles", :action=>"index"}
group_users GET /groups/:group_id/users(.:format) {:controller=>"users", :action=>"index"}(This is likely only to be useful in rare situations. One example would be paginating more than one collection in a single view.)
Controller Methods
OK, so we have our pages represented in our article index route. Let’s turn to the articles controller next.
I believe there is diverging practice on this, but in controllers I always prefer to load the collection and object in before filters, typically along the lines of:
class ArticlesController < ApplicationController before_filter :get_articles before_filter :get_article, :only => [ :show, :edit, :update, :destroy ] before_filter :new_article, :only => [ :new, :create ] # actions here ... protected def get_articles @articles = @user.articles.scoped(:order => "created_at DESC") # or whatever end def get_article @article = @articles.find_from_param(params[:id]) end def new_article @article = @articles.new(params[:article]) end end
It’s a very consistent way to write RESTful controllers. The @articles collection is always created, which is OK, since it’s just a scope or an association and no records are actually loaded. For the member actions, the collection instance is either loaded from the collection or built from it, depending on whether the action is creating a new record (new, create) or modifying an existing once (show, edit, update, destroy).
Using this pattern, paginating the collection fits naturally as another before filter once the collection is set. To this end, Paged Scopes provides a tailored paginate class method to do just that:
class ArticlesController < ApplicationController before_filter :get_articles before_filter :get_article, :only => [ :show, :edit, :update, :destroy ] before_filter :new_article, :only => [ :new, :create ] paginate :articles, :per_page => 3, :path => :page_articles_path ...
This paginate method basically adds another before_filter which loads the current page from the collection. As arguments, it takes an optional collection name and an options hash. If omitted, the collection name is inferred from the controller name. (Hence, in the above example, we could have omitted the :artices arguments and @articles would then be inferred from the ArticlesController name. Hurrah for naming conventions!)
You can pass a few options to the paginate method:
- A :per_page option sets the page size on the collection if you specify it. (This option can be omitted if per_page has already been set on the collection.)
- A :path option will set the path proc for the paginator to be the controller method you specify. The method should take a page and return the path. In the above example we’ve set it to a named route (page_articles_path), but it could equally well be a method you’ve defined later in the controller. (This could be useful if you want to use a polymorphic path, for example.)
- A :name option is available if you want to refer to your pages by a different class name (unlikely).
Any other options will be passed through to the filter definition. So you can use filter options, such as :if, :only and :except, just as you would for any other filter.
Aside from setting the options you specify, the main job of the paginate filter is to set the page as an instance variable. Controller actions will then have a @page variable available to be used for pagination. The page number is determined from three locations in order of priority.
- If an object of the collection is present (an @article, in our example), the page containing that object is loaded (unless the object is a new record).
- Failing that, the request params are examine for a :page_id. If present, that page number is loaded. (This fits with the paged resource routes described earlier.)
- Failing that, the first page is loaded by default.
Loading the page for a member action (show, edit, update) might not seem useful at first. Its utility becomes apparent when we’re redirecting though:
def update if @article.save flash[:notice] = "Success!" redirect_to page_articles_path(@page) else ... end end
The page is used to redirect to the index at the page containing the edited object. Very polite to users! (Views can also link back to the paged index in a similar manner.)
Next Time …
There you have it – a couple of methods that make paging your resources a no-brainer. But I’ve saved one of the best bits for last! In the final installment, I’ll describe the paginator, a super-convenient object for rendering windowed pagination links in your views.
There are a lot of convenient, fast and powerful products.
DVD Ripper http://www.audiotoolsfactory.com/
Blu-ray Cloner http://www.audiotoolsfactory.com/
DVD Cloner http://www.audiotoolsfactory.com/
Blu-ray Ripper http://www.audiotoolsfactory.com/
DVD to AVI http://www.audiotoolsfactory.com/dvd-to-avi.html
DVD to iPod http://www.audiotoolsfactory.com/dvd-to-ipod.html
DVD to MP3 http://www.audiotoolsfactory.com/dvd-to-mp3.html
DVD to MP4 http://www.audiotoolsfactory.com/dvd-to-mp4.html
blu-ray converter http://www.audiotoolsfactory.com/blu-ray-converter.html
convert blu-ray http://www.audiotoolsfactory.com/blu-ray-converter.html
blu-ray to ipod http://www.audiotoolsfactory.com/blu-ray-to-ipod.html
rip blu-ray http://www.audiotoolsfactory.com/blu-ray-ripper.html
blu-ray ripper http://www.audiotoolsfactory.com/blu-ray-ripper.html
Mac DVD Ripper http://www.audiotoolsfactory.com/dvd-ripper-mac.html
mac video converter http://www.audiotoolsfactory.com/video-converter-mac.html
mac dvd to ipod http://www.audiotoolsfactory.com/dvd-ipod-mac.html
Video Converter http://www.audiotoolsfactory.com/video-converter.html
mac video to apple tv http://www.audiotoolsfactory.com/apple-tv-video-mac.html
mac video to apple tv converter http://www.audiotoolsfactory.com/apple-tv-video-mac.html
mac avi to iphone http://www.audiotoolsfactory.com/avi-iphone-mac.html
mac avi to ipod http://www.audiotoolsfactory.com/avi-ipod-mac.html
video to avi http://www.audiotoolsfactory.com/avi-video.html
blu-ray to avi http://www.audiotoolsfactory.com/blu-ray-to-avi.html
blu-ray to hd http://www.audiotoolsfactory.com/blu-ray-to-hd-video.html
blu-ray to mp3 http://www.audiotoolsfactory.com/blu-ray-to-mp3.html
blu-ray to mp4 http://www.audiotoolsfactory.com/blu-ray-to-mp4.html
blu-ray to mpeg http://www.audiotoolsfactory.com/blu-ray-to-mpeg.html
blu-ray to psp http://www.audiotoolsfactory.com/blu-ray-to-psp.html
blu-ray to wmv http://www.audiotoolsfactory.com/blu-ray-to-wmv.html
mac dvd to apple tv http://www.audiotoolsfactory.com/dvd-appletv-mac.html
mac dvd to avi http://www.audiotoolsfactory.com/dvd-avi-mac.html
mac dvd to flv http://www.audiotoolsfactory.com/dvd-flv-mac.html
mac dvd to gphone http://www.audiotoolsfactory.com/dvd-gphone-mac.html
mac dvd to iphone http://www.audiotoolsfactory.com/dvd-iphone-mac.html
mac dvd to ipod http://www.audiotoolsfactory.com/dvd-ipod-mac.html
mac dvd to mp3 http://www.audiotoolsfactory.com/dvd-mp3-mac.html
mac dvd to mp4 http://www.audiotoolsfactory.com/dvd-mp4-mac.html
mac dvd to mpeg http://www.audiotoolsfactory.com/dvd-mpeg-mac.html
mac dvd to psp http://www.audiotoolsfactory.com/dvd-psp-mac.html
mp3 cutter http://www.audiotoolsfactory.com/mp3cutter/mp3cutter.htm
mp3 splitter http://www.audiotoolsfactory.com/mp3cutter/mp3cutter.htm
We can provide you with convenient, fast and powerful products.
http://www.blurayrippers.net/bluraycloner.htm // Blu ray cloner
http://www.blurayrippers.net/blu_ray_ripper_for_mac.htm // Blu ray ripper for mac
http://www.blurayrippers.net/blurayconverter.htm // Blu ray converter
http://www.blurayrippers.net/bluraydisccopy.htm / Blu ray copy
Blu ray ripper http://www.blurayrippers.net
http://www.blurayrippers.net/bluraymaker.htm \\ Blu ray maker
http://www.blurayrippers.net/bestblurayburner.htm // Blu ray burner
http://www.blurayrippers.net/bluraybackup.htm // Blu ray backup
http://www.blurayrippers.net/howtoripabluray.htm // Rip Blu ray
http://www.blurayrippers.net/bluraytoavi.htm // Blu ray to AVI
http://www.blurayrippers.net/howtobackupbluray.htm // backup Blu ray
http://www.blurayrippers.net/howtomakebluray.htm // make Blu ray
http://www.blurayrippers.net/howtoburnbluray.htm // burn Blu ray
http://www.blurayrippers.net/howtoconvertbluray.htm // convert Blu ray
http://www.blurayrippers.net/bluraytohd.htm // Blu ray to HD
http://www.blurayrippers.net/Convert-blu-ray-to-ipad.htm blu ray to ipad
http://www.ripbd.net/blu-ray-converter.htm blu ray converter
http://www.ripbd.net/blu-ray-maker.htm blu ray maker
http://www.ripbd.net/blu-ray-copy.htm blu ray copy
http://www.ripbd.net blu ray ripper
http://www.videotoipadconverter.net ipad converter
http://www.blurayrippers.net/bluraycloner.htm // Blu ray cloner
http://www.blurayrippers.net/blu_ray_ripper_for_mac.htm // Blu ray ripper for mac
http://www.blurayrippers.net/blurayconverter.htm // Blu ray converter
http://www.blurayrippers.net/bluraydisccopy.htm / Blu ray copy
Blu ray ripper http://www.blurayrippers.net
http://www.blurayrippers.net/bluraymaker.htm \\ Blu ray maker
http://www.blurayrippers.net/bestblurayburner.htm // Blu ray burner
http://www.blurayrippers.net/bluraybackup.htm // Blu ray backup
http://www.blurayrippers.net/howtoripabluray.htm // Rip Blu ray
http://www.blurayrippers.net/bluraytoavi.htm // Blu ray to AVI
http://www.blurayrippers.net/howtobackupbluray.htm // backup Blu ray
http://www.blurayrippers.net/howtomakebluray.htm // make Blu ray
http://www.blurayrippers.net/howtoburnbluray.htm // burn Blu ray
http://www.blurayrippers.net/howtoconvertbluray.htm // convert Blu ray
http://www.blurayrippers.net/bluraytohd.htm // Blu ray to HD
http://www.blurayrippers.net/Convert-blu-ray-to-ipad.htm blu ray to ipad
http://www.ripbd.net/blu-ray-converter.htm blu ray converter
http://www.ripbd.net/blu-ray-maker.htm blu ray maker
http://www.ripbd.net/blu-ray-copy.htm blu ray copy
http://www.ripbd.net blu ray ripper
http://www.videotoipadconverter.net ipad converter