There must be a better way to write this code: @project_pages, @projects= paginate :project, :per_page => 10, :conditions => ["account_id = ?", account] ?! If only I could pass the sub-collection account = ... @projects = account.project to paginate, instead of letting it extract it with a find :all + sql conditions Alain. -- Posted via http://www.ruby-forum.com/.
On Dec 15, 2005, at 5:19 PM, Alain Ravet wrote:> > There must be a better way to write this code: > > @project_pages, @projects= paginate :project, > :per_page => 10, > :conditions => ["account_id = ?", account] > > ?! > > If only I could pass the sub-collection > account = ... > @projects = account.project > > to paginate, instead of letting it extract it with a find :all + sql > conditions > >I''ve been wishing for this for a while as well. I''m not sure if all the pieces are in place yet, as I haven''t made a complete prototype, but here''s one piece that might be useful if you''re thinking of fixing this problem: http://dev.rubyonrails.org/ticket/2466 The idea is that you should be able to set a constraint where the code within the block will have certain conditions (like yours) enforced on it. In that way, the pagination methods (or some derivatives) will fetch the correct result set instead of :all. Duane Johnson (canadaduane) _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
Duane > http://dev.rubyonrails.org/ticket/2466 > The idea is that you should be able to set a constraint where .. It would be much simpler/natural to simply feed the prevously fetched collection to paginate. => we could write code like this: @project_pages, @projects= paginate :collection => @john.pending_projects, :per_page => 10 Without a feature like this, we are forced to turn model querying methods - m.pending_projects() - back into sql code for the condition. It''s really unlike Rais. Alain -- Posted via http://www.ruby-forum.com/.
On Dec 16, 2005, at 10:23 AM, Alain Ravet wrote:> Duane >> http://dev.rubyonrails.org/ticket/2466 >> The idea is that you should be able to set a constraint where > .. > > It would be much simpler/natural to simply feed the prevously fetched > collection to paginate. > => we could write code like this: > > @project_pages, @projects= paginate :collection => > @john.pending_projects, > :per_page => 10Well, adapted from API docs <http://api.rubyonrails.org/classes/ ActionController/Pagination.html> : @projects = someperson.projects @project_pages = Paginator.new self, @projects.length, 10, params [''page''] Is this what you are looking for? izidor
On Dec 16, 2005, at 11:26 AM, Izidor Jerebic wrote:> > On Dec 16, 2005, at 10:23 AM, Alain Ravet wrote: > >> Duane >>> http://dev.rubyonrails.org/ticket/2466 >>> The idea is that you should be able to set a constraint where >> .. >> >> It would be much simpler/natural to simply feed the prevously fetched >> collection to paginate. >> => we could write code like this: >> >> @project_pages, @projects= paginate :collection => >> @john.pending_projects, >> :per_page => 10 > > Well, adapted from API docs <http://api.rubyonrails.org/classes/ > ActionController/Pagination.html> : > > @projects = someperson.projects > @project_pages = Paginator.new self, @projects.length, 10, > params[''page''] > > Is this what you are looking for?No, this is not what you are looking for :-) One needs to also limit the @projects, something like this: page = params[''page''].to_i page = 1 if page <= 0 offset = (page - 1) * 10 @projects = someperson.projects[ offset .. offset+10-1] @project_pages = Paginator.new self, @projects.length, 10, params [''page''] izidor
On Dec 16, 2005, at 11:34 AM, Izidor Jerebic wrote:> > On Dec 16, 2005, at 11:26 AM, Izidor Jerebic wrote: > >> >> On Dec 16, 2005, at 10:23 AM, Alain Ravet wrote: >> >>> Duane >>>> http://dev.rubyonrails.org/ticket/2466 >>>> The idea is that you should be able to set a constraint where >>> .. >>> >>> It would be much simpler/natural to simply feed the prevously >>> fetched >>> collection to paginate. >>> => we could write code like this: >>> >>> @project_pages, @projects= paginate :collection => >>> @john.pending_projects, >>> :per_page => 10 >> >> Well, adapted from API docs <http://api.rubyonrails.org/classes/ >> ActionController/Pagination.html> : >> >> @projects = someperson.projects >> @project_pages = Paginator.new self, @projects.length, 10, >> params[''page''] >> >> Is this what you are looking for? > > No, this is not what you are looking for :-) > > One needs to also limit the @projects, something like this: > > page = params[''page''].to_i > page = 1 if page <= 0 > offset = (page - 1) * 10 > @projects = someperson.projects[ offset .. offset+10-1] > > @project_pages = Paginator.new self, @projects.length, 10, params > [''page''] >Heh, third time''s a charm... Object count must be from the full collection. @project_pages = Paginator.new self, someperson.projects.length, 10, params[''page''] All this could be generalized and wrapped in a nice small helper, e.g. paginate_collection or something.... izidor
Izidor Nice but... There''s still a problem: how to have the paginator add parameters in the url? For example, I want to list all the members for a given project, instead of just all the members in the db (scaffold''s default) : part 1: ******* => in the view, I add the ''project'' id as a parameter : <%= link_to project.name, {:action => :list, :project => project} %> => when clicked, it translates into http://localhost:3001/members/list?project=1 (Note the "project=1" at the end of the url) part 2 : ******** In the list action, I filter the members by project def list @project = Project.find(params[:project]) <<- use the filter here records_per_page = 10 page = params[''page''].to_i page = 1 if page <= 0 offset = (page - 1) * records_per_page @members = @project.members[offset .. offset+records_per_page-1] @member_pages = Paginator.new self, @project.members.length, records_per_page, params[''page''] end problem: I cannot have the paginator add/keep "project=1" in the params, so it generates this html <a href="/members/list?page=2">Next page</a> (Note: no more "project=1" in the url) => when I click on "Next page", I get an error because the project id is missing. Any idea? -- Posted via http://www.ruby-forum.com/.
On Friday 16 December 2005 20:45, Alain Ravet wrote:> Izidor > > Nice but... > > There''s still a problem: how to have the paginator add parameters in the > url? > > For example, I want to list all the members for a given project, instead > of just all the members in the db (scaffold''s default) : > > part 1: > ******* > => in the view, I add the ''project'' id as a parameter : > > <%= link_to project.name, > {:action => :list, :project => project} %> > > => when clicked, it translates into > > http://localhost:3001/members/list?project=1 > > (Note the "project=1" at the end of the url) > > > part 2 : > ******** > > In the list action, I filter the members by project > > def list > > @project = Project.find(params[:project]) <<- use the filter here > > records_per_page = 10 > page = params[''page''].to_i > page = 1 if page <= 0 > offset = (page - 1) * records_per_page > @members = @project.members[offset .. offset+records_per_page-1] > @member_pages = Paginator.new self, > @project.members.length, > records_per_page, > params[''page''] > end > > > problem: I cannot have the paginator add/keep "project=1" in the params, > so it generates this html > > <a href="/members/list?page=2">Next page</a> > > (Note: no more "project=1" in the url) > => when I click on "Next page", I get an error because the project id is > missing. > > > Any idea?Keep the project_id in the session, and have it initialized when the list is called with an explicit project_id. def list @project_id = params[:project] || session[:current_project_id] session[:current_project_id] = @project_id @project = Project.find(@project_id) <<- use the filter here records_per_page = 10 page = params[''page''].to_i page = 1 if page <= 0 offset = (page - 1) * records_per_page @members = @project.members[offset .. offset+records_per_page-1] @member_pages = Paginator.new self, @project.members.length, records_per_page, params[''page''] end ----------------------- This will have the nice side effect that any selection of project will be "sticky", so the user can go to view / edit the project, go to other parts of the application and when come back to the list, still it''s the "current" project that is shown.
François, Thanks. I''m spoiled: it''s too much code for my eyes :) It hurts: I keep thinking about where we started : def list @member_pages, @members = paginate :member, :per_page => 10 end All I wanted was a way to avoid adding the ''condition'' clause, because it looked a little ugly!! :) If ''scaffold'' knew how to handle ''belongs_to'', I''m sure somebody would have felt the same pain, and created a clean and more Railish solution. Alain -- Posted via http://www.ruby-forum.com/.
On 12/16/05, Alain Ravet <alainravet-spam2004-/E1597aS9LQAvxtiuMwx3w@public.gmane.org> wrote:> François, > > Thanks. > > I''m spoiled: it''s too much code for my eyes :) It hurts: I keep thinking > about where we started : > > def list > @member_pages, @members = paginate :member, :per_page => 10 > end >Here''s some example code from one of my projects. I can''t remember who sent over the original ''paginate_collection'' code, but please pretend that I''ve given proper credit for the idea. Heh. Hopefully it helps, and won''t make your eyes bleed. Also, hopefully, Gmail won''t kill it with text-wrapping. # This goes in some user library that you can load from environment.rb, or you can put it in controllers/application.rb, etc. def paginate_collection(collection, options = {}) # This helps us paginate collections that are extremely difficult to produce via assocations. # Invoke it from a controller like this: # @pages, @users = paginate_collection(@some_collection, :page => params[:page]) default_options = {:per_page => 10, :page => 1} options = default_options.merge options pages = Paginator.new self, collection.size, options[:per_page], options[:page] first = pages.current.offset last = [first + options[:per_page], collection.size].min slice = collection[first...last] return [pages, slice] end #controller method: def list_exceptions @exceptions_for_user = App.find(:all, :conditions => ["user_id = ? and dispositions.status_code = ''F''", session[:user].id], :include => [:disposition]) @exception_pages, @exceptions paginate_collection(@exceptions_for_user, :page => params[:page]) end
Wilson, I feel I''m very close, but I keep getting a funny error : (full stacktrace at bottom) undefined method `zero?'' for "2":String , where ''2'' is my_collection.size I looked into Rails'' source, and it happens in the Paginator code : def page_count @page_count ||= @item_count.zero? ? 1 : ## <<---- ERROR HERE (q,r=@item_count.divmod(@items_per_page); r==0? q : q+1) end ''@item_count'' seems to be a string. How is this possible: the only place its value is changed is in the constructor: class Paginator ... def initialize(controller, item_count, items_per_page, current_page=1) ... @item_count = item_count || 0 end And ''item_count'', the 2nd parameter, is set to the collection.size pages = Paginator.new self, collection.size, options[:per_page], options[:page] Alain Full code : ---------- class Member_controller < .. def list @project = Project.find(1) @members, @member_pages = paginate_collection @project.members , :page => params[:page] end .. end class ApplicationController < ActionController::Base def paginate_collection(collection, options = {}) # Invoke it from a controller like this: # @pages, @users = paginate_collection(@some_collection, :page => params[:page]) default_options = {:per_page => 10, :page => 1} options = default_options.merge options pages = Paginator.new self, collection.size, options[:per_page], options[:page] first = pages.current.offset # <<------- ERROR OCCURS HERE last = [first + options[:per_page], collection.size].min slice = collection[first...last] return [pages, slice] end end Error Stacktrace : actionpack-1.11.2/... : lib/action_controller/pagination.rb:253:in `page_count'' lib/action_controller/pagination.rb:261:in `has_page_number?'' lib/action_controller/pagination.rb:287:in `initialize'' lib/action_controller/pagination.rb:267:in `new'' lib/action_controller/pagination.rb:267:in `[]'' lib/action_controller/pagination.rb:235:in `current'' #{RAILS_ROOT}/app/controllers/application.rb:11:in `paginate_collection'' #{RAILS_ROOT}/app/controllers/members_controller.rb:12:in `list''
Hrm. Can you really leave out the parentheses when doing multiple-assignment like that? Try using parens in the call to paginate_collection in your controller action. On 12/16/05, Alain Ravet <arav2132-6SW1mVBvVAbXsMajfR9tMA@public.gmane.org> wrote:> Wilson, > > I feel I''m very close, but I keep getting a funny error : (full > stacktrace at bottom) > > undefined method `zero?'' for "2":String > > , where ''2'' is my_collection.size > > > I looked into Rails'' source, and it happens in the Paginator code : > > def page_count > @page_count ||= @item_count.zero? ? 1 : ## <<---- ERROR HERE > (q,r=@item_count.divmod(@items_per_page); > r==0? q : q+1) > end > > > ''@item_count'' seems to be a string. How is this possible: the only place > its value is changed is in the constructor: > > class Paginator > ... > def initialize(controller, item_count, items_per_page, > current_page=1) > ... > @item_count = item_count || 0 > end > > And ''item_count'', the 2nd parameter, is set to the collection.size > pages = Paginator.new self, collection.size, > options[:per_page], options[:page] > > > Alain > > Full code : > ---------- > > class Member_controller < .. > def list > @project = Project.find(1) > @members, @member_pages = paginate_collection @project.members , > :page => params[:page] > end > .. > end > > > > class ApplicationController < ActionController::Base > > def paginate_collection(collection, options = {}) > # Invoke it from a controller like this: > # @pages, @users = paginate_collection(@some_collection, :page => > params[:page]) > > default_options = {:per_page => 10, :page => 1} > options = default_options.merge options > > pages = Paginator.new self, collection.size, > options[:per_page], options[:page] > first = pages.current.offset # <<------- ERROR > OCCURS HERE > last = [first + options[:per_page], collection.size].min > slice = collection[first...last] > > return [pages, slice] > end > end > > > > > > > > > Error Stacktrace : > > actionpack-1.11.2/... : > lib/action_controller/pagination.rb:253:in `page_count'' > lib/action_controller/pagination.rb:261:in `has_page_number?'' > lib/action_controller/pagination.rb:287:in `initialize'' > lib/action_controller/pagination.rb:267:in `new'' > lib/action_controller/pagination.rb:267:in `[]'' > lib/action_controller/pagination.rb:235:in `current'' > #{RAILS_ROOT}/app/controllers/application.rb:11:in `paginate_collection'' > #{RAILS_ROOT}/app/controllers/members_controller.rb:12:in `list'' > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Wilson Bilkovich wrote: > Try using parens in the call to paginate_collection in your controller > action. Same problem, even when I use parentheses : @members, @member_pages = paginate_collection (@project.members , :page => params[:page]) Alain -- Posted via http://www.ruby-forum.com/.
Try taking the space out between paginate_collection and the opening parentheses. Hopefully I''m not leading out astray here. Heh. On 12/17/05, Alain Ravet <alainravet-spam2004-/E1597aS9LQAvxtiuMwx3w@public.gmane.org> wrote:> Wilson Bilkovich wrote: > > Try using parens in the call to paginate_collection in your > controller > > action. > > > Same problem, even when I use parentheses : > > @members, @member_pages = paginate_collection (@project.members , > :page => params[:page]) > > > Alain > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >