KGolbang
KGolbang

Reputation: 445

Rails: will_paginate links generated in context of the controller (self)

I'm using will paginate bootstrap like this:

My model:

class Customer < ActiveRecord::Base

  attr_accessible :city, :country, :name, :street, :zip

  //... more code

  has_many :contacts, :dependent => :destroy, :autosave => true

end


class Contact < ActiveRecord::Base
  attr_accessible :name, :notice, :phone

  //... more code

  belongs_to :customer
end

Gemfile:

gem "will_paginate-bootstrap"

Partial which is able to generate paginated output in contacts/_pageable_contacts.html.erb:

<%
    contacts = contacts.to_a.paginate( :page => params[:page] || 1, :per_page => 5 )
%>
<%= render(:partial => 'contacts/contacts', :locals => {:contacts => contacts})%>
<%= will_paginate contacts, renderer: BootstrapPagination::Rails, remote: true %>

Invocation inside contacts/create.js.erb:

<%
all = @contact.customer.contacts
%>
<%= render :partial => "contacts/pageable_contacts", :locals => { :contacts => all } %>

The links generated by will_paginate are as follows as long as this partial has been rendered in context of the Contacts controller (e.g. views/contacts/create.js.erb):

customers/3/contacts?page=1
customers/3/contacts?page=2

Now, I want to render this partial inside customer/show.html.erb like this:

<%= render :partial => 'contacts/pageable_contacts', :object => @customer.contacts, :as => :contacts %>

But the links returned by will_paginate are customer specific rather than contact specific. Apparently, will_paginate's accessing self (which is CustomerController) to build the links.

customers/3?page=1
customers/3?page=2

How can I tell the partial or will_paginate howto deal with it? Did I misunderstand the concept of MVC, routes or anything else? Am I using the associations between the models in a wrong way?

Any help appreciated! Thanks you SO. golbie

Upvotes: 0

Views: 719

Answers (1)

KGolbang
KGolbang

Reputation: 445

I debugged will_paginate and detected that self is passed as "template":

def will_paginate(collection, options = {})
  # early exit if there is nothing to render
  return nil unless collection.total_pages > 1

  options = WillPaginate::ViewHelpers.pagination_options.merge(options)

  #............. more code

  # render HTML for pagination
  renderer.prepare collection, options, self  #####<====== self is Customers Controller
  renderer.to_html
end

My found a workaround: instead of using "render" mechanism I'm using an ajax request to call the index method of Contacts controller like this:

I. in customers/show.html.erb:

<div id="contacts">
</div>

<%= javascript_tag "ProtoSupport.fetchCustomersContacts('#{customer_contacts_path(@customer)}');" %>
<%= javascript_tag 'ProtoSupport.addAsyncPagination();' %>

II. in assets/javascript/application.js these two new methods in ProtoSupport:

        fetchCustomersContacts : function(path) {
            $.getScript(path);

        },
        addAsyncPagination : function() {
            $(function() {
                $(".pagination a").on("click", function() {
                    if( $(this).attr('href') == '#' ) return false;
                    $(".pagination").html("Page is loading...");
                    $.getScript(this.href);
                    return false;
                });
            });
        }

The links are correct now (e.g. 'http://localhost:3000/customers/3/contacts?page=16') and when I click on a page the new data are loaded asynchronously.

golbie

Upvotes: 1

Related Questions