Multiple Pagination

I have the following:

def index
begin
@restaurant_pages, @restaurants = paginate :restaurants,
:order => (params[
:sort ] || “name”),
:per_page => 2
@cuisines = Cuisine.find_all
rescue
redirect_to :action => :index
end
end

sort by cuisine

def sort_by_cuisine
begin
@restaurant_pages, @restaurants = paginate :restaurants,
:conditions => [
“cuisine_id = :id”, params ],
:order => (params[
:sort ] || “name”),
:per_page => 2
@cuisines = Cuisine.find_all
rescue
redirect_to :action => :sort_by_cuisine
end
end

def by_letter
@restaurant_pages, @restaurants = paginate :restaurants,
:conditions => [ “name
LIKE ?”, params[ :letter ] + “%” ],
:order => (params[ :sort
] || “name”),
:per_page => 2
@cuisines = Cuisine.find_all
end

This allows me to sort my results nicely by letter. However, I want to
be able to sort by letter after filtering by cuisine, so the sort by
letter method is called only on the restaurants that match some cuisine.
Instead of writing another method “sort_by_cuisine_by_letter” is there
an easier way to do this, whilst keeping the pagination? Thanks!!

in your model, you can define <=> which is how you can sort an object.
you
also need to include Comparable into your model. And since you’re
trying to
sort cuisines, this would go in your Cuisine model. In your <=> method,
you
would first compare the cuisine names, then the restaurant names. (most
likely you’ll have to implement a sortable method in your restaraunt
model
as well) After you’ve defined that method, you can call
@cuisines.sort!,
and you should have your ordered list of cuisines.

For more information, check out how to use
Comparablehttp://www.ruby-doc.org/core/classes/Comparable.html.
plus this moves more of your code to the model level, allowing you to
reuse
it in other places, thus making your code more DRY.

Mike W. wrote:

in your model, you can define <=> which is how you can sort an object.
you
also need to include Comparable into your model. And since you’re
trying to
sort cuisines, this would go in your Cuisine model. In your <=> method,
you
would first compare the cuisine names, then the restaurant names. (most
likely you’ll have to implement a sortable method in your restaraunt
model
as well) After you’ve defined that method, you can call
@cuisines.sort!,
and you should have your ordered list of cuisines.

For more information, check out how to use
Comparablehttp://www.ruby-doc.org/core/classes/Comparable.html.
plus this moves more of your code to the model level, allowing you to
reuse
it in other places, thus making your code more DRY.

I’m not sure how this solves the problem though. The sort by cuisine
method only displays restaurants with a specified cuisine. I then want
to be able to display only those restaurants that begin with a certain
letter, whilst maintaining pagination. At the moment I can display only
restaurants that start with a particular letter and I can display only
restaurants that are of some cuisine, but I can’t seem to combine them.
Just re-explaining incase you mis-interpreted the question, although I
may have mis-interpreted your reply! Thanks in advance.

To get a better understanding of your problem, are you trying to get a
list
of restaraunts based on 2 criteria: serves a certain cuisine and name
starts
with a certain letter?

Mike W. wrote:

To get a better understanding of your problem, are you trying to get a
list
of restaraunts based on 2 criteria: serves a certain cuisine and name
starts
with a certain letter?

Thats exactly right, but instead of a list, more like an array of
objects which I can paginate.

in that case, since it seems your problem isn’t getting the specific
data, I
think I can help you. I don’t use paginate anymore. Instead in all of
my
applications I put this in the application controller

Paginate an existing resultset.

Example:

@pages, @users = paginate_collection User.find_custom_query, :page

=>
@params[:page]
def paginate_collection(collection, options = {})
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

it allows you to paginate any type of collection. I hope you find this
to
be helpful. Works the same way that regular paginate works, except it
allows more flexibility in what you want to paginate.

Mike W. wrote:

in that case, since it seems your problem isn’t getting the specific
data, I
think I can help you. I don’t use paginate anymore. Instead in all of
my
applications I put this in the application controller

Paginate an existing resultset.

Example:

@pages, @users = paginate_collection User.find_custom_query, :page

=>
@params[:page]
def paginate_collection(collection, options = {})
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

it allows you to paginate any type of collection. I hope you find this
to
be helpful. Works the same way that regular paginate works, except it
allows more flexibility in what you want to paginate.

right thanks I’ll give it a try. how exactly does it offer more
flexibility, just so I can get it clear in my head?

actually, I think I misread your question again. I’m pretty sure now
that
the answer to your question is no, there is not really a better way of
doing
it other than creating a method called find_by_cuisine_and_first_letter.
but you should put that method, as well as your other ones, into your
model.

so if you were to start using the paginate_collection code I sent you,
your
code would look something like this: (this isn’t debugged so no
guarantees)

Restaraunt Model----
def self.find_by_first_letter(letter)
Restaraunt.find(:all, :conditions => [“name like ?”, letter + “%”])
end

def self.find_by_cuisine_and_first_letter(cuisine, letter)
Restaraunt.find(:all, :conditions => [“name like ? AND cuisine_id = ?”,
letter + “%”, ])
end
Controller----
@restaraunt_pages, @restaraunts = paginate_collection
Restaurant.find_by_cuisine_id(params[:letter]), :page => @params[:page]

  • note: you get find_by_cuisine_id for free

i hope I’m finally on the right track for helping you

yes, but I think it’d be trickier to do that since you’ll have to
basically
build a string depending upon which arguments are sent in. essentially
it’d
be your condition statement that you’d have to create, and then you have
to
deal with whether or not to add an “AND” in your condition.

but if that’s the route that you want to go, then you’d create a
function in
your model that takes in parameters that are nil by default

def my_find_method(letter = nil, cuisine = nil)
body
end

and in your body build your condition statement for finding the
restaraunts
you want, depending on the presence of letter and/or cuisine

not exactly a method I would recommend, but possible

Mike W. wrote:

actually, I think I misread your question again. I’m pretty sure now
that
the answer to your question is no, there is not really a better way of
doing
it other than creating a method called find_by_cuisine_and_first_letter.
but you should put that method, as well as your other ones, into your
model.

so if you were to start using the paginate_collection code I sent you,
your
code would look something like this: (this isn’t debugged so no
guarantees)

Restaraunt Model----
def self.find_by_first_letter(letter)
Restaraunt.find(:all, :conditions => [“name like ?”, letter + “%”])
end

def self.find_by_cuisine_and_first_letter(cuisine, letter)
Restaraunt.find(:all, :conditions => [“name like ? AND cuisine_id = ?”,
letter + “%”, ])
end
Controller----
@restaraunt_pages, @restaraunts = paginate_collection
Restaurant.find_by_cuisine_id(params[:letter]), :page => @params[:page]

  • note: you get find_by_cuisine_id for free

i hope I’m finally on the right track for helping you

Yeah I think you’ve cracked it now. Is there no way of doing some kind
of optional thing in one method - like always display every restaurant
belonging to a particular cuisine UNLESS a letter is specified otherwise
display only restaurants beginning with that letter. If you see what I
mean. Thanks in advance, you’ve been a great help.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs