Saturday, February 21, 2009

Using will_paginate rails plugin with ajax.

will_paginate is great, but... it doesnt support ajax, here the developer explains why.

But actually, it is very common that we would like to use will_paginate with ajax.

On this great post, it explains the hack (READ THAT ARTICLE BEFORE). But how can we use it? for example if we want to update a partial using the collection that returns me the "paginate" method added by the plugin in any active record class.

This is what i did:

First i added the helper(in the mentioned article explains how):



class RemoteLinkRenderer < WillPaginate::LinkRenderer
def prepare(collection, options, template)
#@remote = options.delete(:remote) || {} #(1)
options.delete(:remote) #(2)
@remote = options || {} #(3)
super
end

protected def page_link(page, text, attributes = {})
@template.link_to_remote(text, {:url => url_for(page), :method =>:get}.merge(@remote))
end
end



The options parameter of the "prepare" method, is the hash that will be passed to the options parameter of the link_to_remote helper, but i had to change lines (2) and (3) instead of (1), because the ruby Hash delete method returns the associated value of the key instead of the resulting hash.

So, suppose i want to render a list of users:

This is my controller method:



def index
@users = User.paginate(...options..., :page => params[:page], :per_page => 5)
respond_to do |format|
format.html
format.js { render :action => 'show' } #(4)
end
end



and this is my view (index.html.erb)



<p>
<div id="paginate_refresh">
<%= will_paginate (@users, :renderer => 'RemoteLinkRenderer',
:loading => "some_js_function()", :complete => "some_other_js_function()") %>
</div>
</p>
<p>
<div id="user_refresh">
<%= render :partial => "user", :collection => @users %>
</div>
</p>



I have a _user.html.erb partial with the user information(i will not show it here because it doesn't matter).

My idea was to use 2 different divs for updating the information and the pagination links.

As you can see i also pass to the will_paginate helper method, the callbacks of my ajax request, this options will go directly to the couple of link_to_remote helpers that the will_paginate helper method renders, you can use here all the options provided by link_to_remote helpers.

In the controller method at (4), i render 'show', which is the rjs template(show.js.rjs) that will be rendered when the call is an ajax request.

And here is this template:



page.replace_html 'user_refresh', :partial => "user", :collection => @users
page.replace_html 'paginate_refresh', will_paginate (@users, :renderer =>'RemoteLinkRenderer',
:loading => "some_js_function()", :complete => "some_other_js_function()")



And that's it!

I just refresh the two divs with the new information and the new will_paginate links.

Any comments or questions, please leave a message.

Bye