yeah, that’s what I guess I’ll have to end up doing… I wanted to
avoid this since I’ll end up duplicating my find method wherever I
need to paginate the list of tickets for an Event… Using
@event.tickets.paginate if much preferred, but unfortunately it
doesn’t work. If anyone has any other ideas, please let me know, as
I’ve come across this problem more than once and would like to figure
out an ideal solution. Thanks,
OK, first the disclaimer:
I’ve only been using Ruby/Rails for a few weeks, so am very new to
this, and so it is entirely feasible that there is something hideously
wrong with my solution; however, this is what I’ve come up with to
solve this problem for me:
First of all, I have defined a Class called PaginatableFinder (it’s
the third name it’s had in as many hours):
class PaginatableFinder
attr_reader :parent
def initialize(parent, method, *args, &extension)
@parent, @method, @args = parent, method, args
# if a block is given, use it to exetend this object
if block_given?
extend(Module.new(&extension))
end
end
define a paginate method to gracefuly handle pagination
def paginate(paginate_options = nil)
# replace ‘find’ with ‘paginate’ in the method name
@method = @method.to_s.sub(‘find’, ‘paginate’).to_sym
# get the options from the arguments, or create an empty hash
options = @args.last.is_a?(Hash) ? @args.pop : {}
# merge the paginate options in with the standard options, if
necessary
if paginate_options
options.merge!(paginate_options)
(paginate_options[:conditions] << ’ and ’ <<
options[:conditions]) if paginate_options[:conditions] &&
options[:conditions]
end
# add the options back to the end of the arguments
@args << options
self
end
missing methods should be passed to the object we are proxying
def method_missing(name, *args, &block)
object.send(name, *args, &block)
end
define private method for getting the object we are proxying
private
def object
# get the object by seding the method and args to the parent
object
@object ||= @parent.send(@method, *(@args))
end
end
Then, in my model, I can do things like:
has_many :favourites, :order => :id do
def with_recommendations
PaginatableFinder.new(
self, :find, :all,
:joins => ‘, recommendations’,
:select => ‘favourites.*’,
:group => “recommender_id”,
:conditions => "recommender_type = ‘Favourite’ and
favourites.id = recommender_id ")
end
end
this allows me, to do the following in my controller:
@user.favourites.with_recommendations
or
@user.favourites.with_recommendations.paginate :page => params[:page]
It also allows you to extend extended associations, so I can now do
the following in my model:
has_many :reviews, :order => :position do
def positive
PaginatableFinder.new(self, :find, :all, :conditions => 'stars
= 3’) do
def with_recommendations
PaginatableFinder.new(
parent, :find, :all,
:joins => ‘, recommendations’,
:select => ‘reviews.*’,
:group => “recommender_id”,
:conditions => "stars >= 3 and recommender_type = ‘Review’
and reviews.id = recommender_id ")
end
end
end
end
so I can then do any of the following in my controller:
@user.reviews.positive
@user.reviews.positive.paginate :page => params[:page]
@user.reviews.positive.with_recommendations
@user.reviews.positive.with_recommendations.paginate :page =>
params[:page]
I hope this helps others, and would be massively grateful for any
advice on how I can improve it.
Cheers
Luke.