Hi everyone, I''m at the end of my rope on this. I can''t get pagination to work with anything but a standard find on a model. If I try to do a search and customize the pagination, I get lots of different variations. My thought was to have the list action do what it does, but to pass it a list of search conditions from the search action. So, if search determines that we need to get a list of all people in X department, it sets up searchconditions and tries to pass it to list. No luck there. My basic question is, what''s the best practice way to paginate over custom finds? The search results usually come up ok, it''s just that the pagination links don''t pass on the right parameters, so they either don''t work, or they just go back to the regular list, even though the action is search (in the URL). The most recent attempt has normal listings working correctly, but when I perform a search (which displays correctly) and click on any of the pagination links, since there''s no passing of the search variables. I know how to do this, as I''ve done it a million times in other projects, but I can''t find the Rails way to do this that makes me say, "Oh, magic!" And, since I''m using rails, I''d rather not go and build this the way I would have in Perl. I''m sorry if I come off as harsh, but I''m incredibly frustrated by this. I''ve been hacking on it for hours now, and I can''t launch this version of my app without proper pagination. The deadline is today, and I figured this would be a lot easier than it seems to be. Code: Controller: def list @person_pages, @people = paginate :person, :order => ''last_name ASC'', :per_page => 20 end def search searchconditions = [] if params.include?(:letter) searchconditions = ["LOWER(last_name) LIKE ?", params[:letter].to_str + "%"] elsif params.include?(:department) searchconditions = ["department_id = ?", params[:department]] elsif session[:q] if params[:q] session[:q] = params[:q].downcase searchconditions = [ "LOWER(username) LIKE ? OR LOWER(first_name) LIKE ? OR LOWER(last_name) LIKE ? OR LOWER(preferred_name) LIKE ?", "%" + session[:q] + "%", "%" + session[:q] + "%", "%" + session[:q] + "%", "%" + session[:q] + "%" ] end else session[:q] = '''' end if searchconditions.empty? flash[:note] = "You must enter a search phrase to search." redirect_to :action => "list" else @person_pages, @people = paginate :person, :per_page => 20, :conditions => searchconditions, :order => ''last_name ASC'' render :action => "list" end end View: <%= link_to "Previous", { :page => @person_pages.current.previous } if @person_pages.current.previous -%> <% pagination_links_each(@person_pages, :window_size => 4) do |n| %> <a href=''?page=<%= n %>''><%= n %></a> <% end %> <%= link_to "Next", { :page => @person_pages.current.next } if @person_pages.current.next -%> Resources I''ve used to (it seems) no avail: http://api.rubyonrails.com/classes/ActionController/Pagination.html http://wiki.rubyonrails.com/rails/pages/HowtoPagination http://bigbold.com/snippets/posts/show/389 http://railsexpress.de/blog/articles/2005/11/04/faster-pagination
Pagination can be a little frustrating, but your example doesn''t look too bad. If I understand your question, you''re just having problems w/ the links passing the correct parameters? Just use this: <%= link_to "Previous", { :page => @person_pages.current.previous, :letter => params[:letter], :department => params[:department], :q => params[:q] } if @person_pages.current.previous -%> <% pagination_links_each(@person_pages, :window_size => 4) do |n| - %> <%= link_to n,{:page => n, :letter => params[:letter], :department => params[:department], :q => params[:q]} %> <% end %> <%= link_to "Next", { :page => @person_pages.current.next , :letter => params[:letter], :department => params[:department], :q => params[:q] } if @person_pages.current.next -%> The "magick" is rails will only supply parameters on the query string if their params has a value (ie, each link won''t have &letter=&department=&q=) Also, your searchcondition can be more easily written as: searchconditions = [ "LOWER(username) LIKE :q OR LOWER(first_name) LIKE :q OR LOWER(last_name) LIKE :q OR LOWER(preferred_name) LIKE :q", { :q => "%#{session[:q]}%" }] -----Original Message----- From: rails-bounces@lists.rubyonrails.org on behalf of Sean Hussey Sent: Tue 1/31/2006 10:39 AM To: Rails@lists.rubyonrails.org Subject: [Rails] Pagination - why is it this hard? Hi everyone, I''m at the end of my rope on this. I can''t get pagination to work with anything but a standard find on a model. If I try to do a search and customize the pagination, I get lots of different variations. My thought was to have the list action do what it does, but to pass it a list of search conditions from the search action. So, if search determines that we need to get a list of all people in X department, it sets up searchconditions and tries to pass it to list. No luck there. My basic question is, what''s the best practice way to paginate over custom finds? The search results usually come up ok, it''s just that the pagination links don''t pass on the right parameters, so they either don''t work, or they just go back to the regular list, even though the action is search (in the URL). The most recent attempt has normal listings working correctly, but when I perform a search (which displays correctly) and click on any of the pagination links, since there''s no passing of the search variables. I know how to do this, as I''ve done it a million times in other projects, but I can''t find the Rails way to do this that makes me say, "Oh, magic!" And, since I''m using rails, I''d rather not go and build this the way I would have in Perl. I''m sorry if I come off as harsh, but I''m incredibly frustrated by this. I''ve been hacking on it for hours now, and I can''t launch this version of my app without proper pagination. The deadline is today, and I figured this would be a lot easier than it seems to be. Code: Controller: def list @person_pages, @people = paginate :person, :order => ''last_name ASC'', :per_page => 20 end def search searchconditions = [] if params.include?(:letter) searchconditions = ["LOWER(last_name) LIKE ?", params[:letter].to_str + "%"] elsif params.include?(:department) searchconditions = ["department_id = ?", params[:department]] elsif session[:q] if params[:q] session[:q] = params[:q].downcase searchconditions = [ "LOWER(username) LIKE ? OR LOWER(first_name) LIKE ? OR LOWER(last_name) LIKE ? OR LOWER(preferred_name) LIKE ?", "%" + session[:q] + "%", "%" + session[:q] + "%", "%" + session[:q] + "%", "%" + session[:q] + "%" ] end else session[:q] = '''' end if searchconditions.empty? flash[:note] = "You must enter a search phrase to search." redirect_to :action => "list" else @person_pages, @people = paginate :person, :per_page => 20, :conditions => searchconditions, :order => ''last_name ASC'' render :action => "list" end end View: <%= link_to "Previous", { :page => @person_pages.current.previous } if @person_pages.current.previous -%> <% pagination_links_each(@person_pages, :window_size => 4) do |n| %> <a href=''?page=<%= n %>''><%= n %></a> <% end %> <%= link_to "Next", { :page => @person_pages.current.next } if @person_pages.current.next -%> Resources I''ve used to (it seems) no avail: http://api.rubyonrails.com/classes/ActionController/Pagination.html http://wiki.rubyonrails.com/rails/pages/HowtoPagination http://bigbold.com/snippets/posts/show/389 http://railsexpress.de/blog/articles/2005/11/04/faster-pagination _______________________________________________ Rails mailing list Rails@lists.rubyonrails.org http://lists.rubyonrails.org/mailman/listinfo/rails -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060131/a1b109de/attachment.html
If paginate won''t work for your custom find try creating your own Paginator instead. It''s a few more steps but it''s flexible and nothing to be afraid of. Use the techniques on this page under Custom Pagination: http://wiki.rubyonrails.com/rails/pages/HowtoPagination Focus on getting the elements of the Paginator object together: 1. count of ALL items in the found set 2. number of items per page 3. current page Then execute the custom find you want. If it''s a small data set you can find the full set, count it and then use it on the page. If it''s a large data set you should perform a count of all the items then do a find for only the current range (using the offset). Email me directly if you still have problems and I''ll try to help more. Kevin Skoglund
You might also want to look at paginating prefetched collections: http://rails.techno-weenie.net/question/2006/1/10/passing_specific_records_to_the_paginator Check out solution number two. On 1/31/06, Kevin Skoglund <kevin@pixelandpress.com> wrote:> If paginate won''t work for your custom find try creating your own > Paginator instead. It''s a few more steps but it''s flexible and > nothing to be afraid of. > > Use the techniques on this page under Custom Pagination: > http://wiki.rubyonrails.com/rails/pages/HowtoPagination > > Focus on getting the elements of the Paginator object together: > 1. count of ALL items in the found set > 2. number of items per page > 3. current page > > Then execute the custom find you want. If it''s a small data set you > can find the full set, count it and then use it on the page. If it''s > a large data set you should perform a count of all the items then do > a find for only the current range (using the offset). > > Email me directly if you still have problems and I''ll try to help more. > > Kevin Skoglund > > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-- -------------------------------------------------------------------- I am Mark Daggett and I approve this message.
Solution number two implies that you have to select the entire collection first and then use that (possibly massive data set) for the pagination. Depends on the size of the data set, but that solution could be very, very suboptimal. For large tables, it''s better to do a count_by_sql first and then just fetch the records you need for the given page. On Jan 31, 2006, at 11:30 AM, M Daggett wrote:> You might also want to look at paginating prefetched collections: > > http://rails.techno-weenie.net/question/2006/1/10/ > passing_specific_records_to_the_paginator > > Check out solution number two. > > > On 1/31/06, Kevin Skoglund <kevin@pixelandpress.com> wrote: >> If paginate won''t work for your custom find try creating your own >> Paginator instead. It''s a few more steps but it''s flexible and >> nothing to be afraid of. >> >> Use the techniques on this page under Custom Pagination: >> http://wiki.rubyonrails.com/rails/pages/HowtoPagination >> >> Focus on getting the elements of the Paginator object together: >> 1. count of ALL items in the found set >> 2. number of items per page >> 3. current page >> >> Then execute the custom find you want. If it''s a small data set you >> can find the full set, count it and then use it on the page. If it''s >> a large data set you should perform a count of all the items then do >> a find for only the current range (using the offset). >> >> Email me directly if you still have problems and I''ll try to help >> more. >> >> Kevin Skoglund >> >> >> _______________________________________________ >> Rails mailing list >> Rails@lists.rubyonrails.org >> http://lists.rubyonrails.org/mailman/listinfo/rails >> > > > -- > -------------------------------------------------------------------- > I am Mark Daggett and I approve this message. > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails
Wow, what an outpouring! Big Thank Yous to Jon, Kevin, Mark, and "ym" on #rubyonrails. I think I''ve got this going now. The approach I went with was to create a conditions array in my search action, save it into a session variable, and then redirect_to the list action. The list action checks for the variable (if nothing, it uses "1 = 1") and runs the find. So the conditions stay current in the session until another search is run. Your emails have shown me a few more approaches I''m going to need to look at as my searches get more complex. The bit from Kevin about making my own paginator...y''know, it was just that phrase that changed my thinking of "hack this piece of code to work for me" to, well, "make my own paginator." Again, thank you all so much. It seems like a silly little thing to get stuck on. I really appreciate the help. Sean On 1/31/06, Jon Gubman <jgubman@looksmart.net> wrote:> > > Pagination can be a little frustrating, but your example doesn''t look too > bad. > > If I understand your question, you''re just having problems w/ the links > passing the correct parameters? > > Just use this: > <%= link_to "Previous", { :page => @person_pages.current.previous, :letter > => params[:letter], :department => params[:department], :q => params[:q] } > if > @person_pages.current.previous -%> > <% pagination_links_each(@person_pages, :window_size => 4) > do |n| - %> > <%= link_to n,{:page => n, :letter => params[:letter], :department => > params[:department], :q => params[:q]} %> > <% end %> > <%= link_to "Next", { :page => @person_pages.current.next , :letter => > params[:letter], :department => params[:department], :q => params[:q] } if > @person_pages.current.next -%> > > The "magick" is rails will only supply parameters on the query string if > their params has a value (ie, each link won''t have &letter=&department=&q=) > > Also, your searchcondition can be more easily written as: > searchconditions = [ "LOWER(username) LIKE :q OR > LOWER(first_name) LIKE :q OR LOWER(last_name) LIKE :q OR > LOWER(preferred_name) LIKE :q", { :q => "%#{session[:q]}%" }] > > > -----Original Message----- > From: rails-bounces@lists.rubyonrails.org on behalf of > Sean Hussey > Sent: Tue 1/31/2006 10:39 AM > To: Rails@lists.rubyonrails.org > Subject: [Rails] Pagination - why is it this hard? > > Hi everyone, > > I''m at the end of my rope on this. I can''t get pagination to work > with anything but a standard find on a model. If I try to do a search > and customize the pagination, I get lots of different variations. > > My thought was to have the list action do what it does, but to pass it > a list of search conditions from the search action. So, if search > determines that we need to get a list of all people in X department, > it sets up searchconditions and tries to pass it to list. No luck > there. > > My basic question is, what''s the best practice way to paginate over > custom finds? The search results usually come up ok, it''s just that > the pagination links don''t pass on the right parameters, so they > either don''t work, or they just go back to the regular list, even > though the action is search (in the URL). > > The most recent attempt has normal listings working correctly, but > when I perform a search (which displays correctly) and click on any of > the pagination links, since there''s no passing of the search > variables. > > I know how to do this, as I''ve done it a million times in other > projects, but I can''t find the Rails way to do this that makes me say, > "Oh, magic!" And, since I''m using rails, I''d rather not go and build > this the way I would have in Perl. > > I''m sorry if I come off as harsh, but I''m incredibly frustrated by > this. I''ve been hacking on it for hours now, and I can''t launch this > version of my app without proper pagination. The deadline is today, > and I figured this would be a lot easier than it seems to be. > > Code: > Controller: > def list > @person_pages, @people = paginate :person, :order => ''last_name > ASC'', :per_page => 20 > end > > def search > searchconditions = [] > if params.include?(:letter) > searchconditions = ["LOWER(last_name) LIKE ?", > params[:letter].to_str + "%"] > elsif params.include?(:department) > searchconditions = ["department_id = ?", params[:department]] > elsif session[:q] > if params[:q] > session[:q] = params[:q].downcase > searchconditions = [ "LOWER(username) LIKE ? OR > LOWER(first_name) LIKE ? OR LOWER(last_name) LIKE ? OR > LOWER(preferred_name) LIKE ?", > "%" + session[:q] + "%", > "%" + session[:q] + "%", > "%" + session[:q] + "%", > "%" + session[:q] + "%" ] > end > else > session[:q] = '''' > end > if searchconditions.empty? > flash[:note] = "You must enter a search phrase to search." > redirect_to :action => "list" > else > @person_pages, @people = paginate :person, :per_page => 20, > :conditions => searchconditions, :order => ''last_name ASC'' > render :action => "list" > end > end > > View: > <%= link_to "Previous", { :page => @person_pages.current.previous } if > @person_pages.current.previous -%> > <% pagination_links_each(@person_pages, :window_size => 4) > do |n| %> > <a href=''?page=<%= n %>''><%= n %></a> > <% end %> > <%= link_to "Next", { :page => @person_pages.current.next } if > @person_pages.current.next -%> > > Resources I''ve used to (it seems) no avail: > > http://api.rubyonrails.com/classes/ActionController/Pagination.html > http://wiki.rubyonrails.com/rails/pages/HowtoPagination > http://bigbold.com/snippets/posts/show/389 > http://railsexpress.de/blog/articles/2005/11/04/faster-pagination > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails > > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails > > >
I just wanted to thank everyone again for helping me out yesterday. I pushed the deadline by a couple of hours, but the app is launched and working perfectly. Once again, the Rails community saves someone''s butt. :) Sean On 1/31/06, Sean Hussey <seanhussey@gmail.com> wrote:> Wow, what an outpouring! Big Thank Yous to Jon, Kevin, Mark, and "ym" > on #rubyonrails. I think I''ve got this going now. > > The approach I went with was to create a conditions array in my search > action, save it into a session variable, and then redirect_to the list > action. The list action checks for the variable (if nothing, it uses > "1 = 1") and runs the find. So the conditions stay current in the > session until another search is run. > > Your emails have shown me a few more approaches I''m going to need to > look at as my searches get more complex. > > The bit from Kevin about making my own paginator...y''know, it was just > that phrase that changed my thinking of "hack this piece of code to > work for me" to, well, "make my own paginator." > > Again, thank you all so much. It seems like a silly little thing to > get stuck on. I really appreciate the help. > > Sean > > On 1/31/06, Jon Gubman <jgubman@looksmart.net> wrote: > > > > > > Pagination can be a little frustrating, but your example doesn''t look too > > bad. > > > > If I understand your question, you''re just having problems w/ the links > > passing the correct parameters? > > > > Just use this: > > <%= link_to "Previous", { :page => @person_pages.current.previous, :letter > > => params[:letter], :department => params[:department], :q => params[:q] } > > if > > @person_pages.current.previous -%> > > <% pagination_links_each(@person_pages, :window_size => 4) > > do |n| - %> > > <%= link_to n,{:page => n, :letter => params[:letter], :department => > > params[:department], :q => params[:q]} %> > > <% end %> > > <%= link_to "Next", { :page => @person_pages.current.next , :letter => > > params[:letter], :department => params[:department], :q => params[:q] } if > > @person_pages.current.next -%> > > > > The "magick" is rails will only supply parameters on the query string if > > their params has a value (ie, each link won''t have &letter=&department=&q=) > > > > Also, your searchcondition can be more easily written as: > > searchconditions = [ "LOWER(username) LIKE :q OR > > LOWER(first_name) LIKE :q OR LOWER(last_name) LIKE :q OR > > LOWER(preferred_name) LIKE :q", { :q => "%#{session[:q]}%" }] > > > > > > -----Original Message----- > > From: rails-bounces@lists.rubyonrails.org on behalf of > > Sean Hussey > > Sent: Tue 1/31/2006 10:39 AM > > To: Rails@lists.rubyonrails.org > > Subject: [Rails] Pagination - why is it this hard? > > > > Hi everyone, > > > > I''m at the end of my rope on this. I can''t get pagination to work > > with anything but a standard find on a model. If I try to do a search > > and customize the pagination, I get lots of different variations. > > > > My thought was to have the list action do what it does, but to pass it > > a list of search conditions from the search action. So, if search > > determines that we need to get a list of all people in X department, > > it sets up searchconditions and tries to pass it to list. No luck > > there. > > > > My basic question is, what''s the best practice way to paginate over > > custom finds? The search results usually come up ok, it''s just that > > the pagination links don''t pass on the right parameters, so they > > either don''t work, or they just go back to the regular list, even > > though the action is search (in the URL). > > > > The most recent attempt has normal listings working correctly, but > > when I perform a search (which displays correctly) and click on any of > > the pagination links, since there''s no passing of the search > > variables. > > > > I know how to do this, as I''ve done it a million times in other > > projects, but I can''t find the Rails way to do this that makes me say, > > "Oh, magic!" And, since I''m using rails, I''d rather not go and build > > this the way I would have in Perl. > > > > I''m sorry if I come off as harsh, but I''m incredibly frustrated by > > this. I''ve been hacking on it for hours now, and I can''t launch this > > version of my app without proper pagination. The deadline is today, > > and I figured this would be a lot easier than it seems to be. > > > > Code: > > Controller: > > def list > > @person_pages, @people = paginate :person, :order => ''last_name > > ASC'', :per_page => 20 > > end > > > > def search > > searchconditions = [] > > if params.include?(:letter) > > searchconditions = ["LOWER(last_name) LIKE ?", > > params[:letter].to_str + "%"] > > elsif params.include?(:department) > > searchconditions = ["department_id = ?", params[:department]] > > elsif session[:q] > > if params[:q] > > session[:q] = params[:q].downcase > > searchconditions = [ "LOWER(username) LIKE ? OR > > LOWER(first_name) LIKE ? OR LOWER(last_name) LIKE ? OR > > LOWER(preferred_name) LIKE ?", > > "%" + session[:q] + "%", > > "%" + session[:q] + "%", > > "%" + session[:q] + "%", > > "%" + session[:q] + "%" ] > > end > > else > > session[:q] = '''' > > end > > if searchconditions.empty? > > flash[:note] = "You must enter a search phrase to search." > > redirect_to :action => "list" > > else > > @person_pages, @people = paginate :person, :per_page => 20, > > :conditions => searchconditions, :order => ''last_name ASC'' > > render :action => "list" > > end > > end > > > > View: > > <%= link_to "Previous", { :page => @person_pages.current.previous } if > > @person_pages.current.previous -%> > > <% pagination_links_each(@person_pages, :window_size => 4) > > do |n| %> > > <a href=''?page=<%= n %>''><%= n %></a> > > <% end %> > > <%= link_to "Next", { :page => @person_pages.current.next } if > > @person_pages.current.next -%> > > > > Resources I''ve used to (it seems) no avail: > > > > http://api.rubyonrails.com/classes/ActionController/Pagination.html > > http://wiki.rubyonrails.com/rails/pages/HowtoPagination > > http://bigbold.com/snippets/posts/show/389 > > http://railsexpress.de/blog/articles/2005/11/04/faster-pagination > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > > >