Unwanted form parameters being appended to pagination links
Asked Answered
L

4

12

I have a page which is used for searching through listings by submitting data using the supplied forms. The form parameters are submitted via ajax (post request), a new record is created in the searches table and then the listings are displayed (dynamically, on the same page the form is submitted from) via the show action for this record.

The results have pagination links provided by kaminari like so:

<%= paginate matches, 
  :params => {:controller => 'searches',
  # I have to specify the id because my searches are stored in the database
  :action => 'show', :id => search.id},
  :remote => true %>

Note that the pagination links are dynamically included to the page. So, when I do new search and get new listings, the server re-renders the pagination links.

Here is my show action in the searches controller

def show
  @search = Search.includes(:rate).find(params[:id])
  @matches = @search.matches.order(sort_column + " " + sort_direction).page(params[:page])

  respond_to do |format|
    format.html
    format.xml { render :xml => @matches }
    format.js
  end
end

For some reason I can't figure out, all of the parameters I use in the search forms (and there's a lot of them) are being attached to the kaminari pagination urls giving me hrefs like this:

<a href="/searches/145?massive parameter list omitted" data-remote="true" rel="next">2</a>

The omitted parameter list is so long that it's too large to be a valid GET request and I get a 414 error code.

As you can see from the searches -> show action I have above, it's unnecessary for the pagination links to have all this info appended. All they need is the route, id and page number.

How do I prevent this from happening?

By the way, I've tried setting :method => :post in the kaminari options. Doesn't seem to help. I'm using kaminari v 0.12.4 (latest) and Rails 3.1.rc4.

Leatherback answered 13/6, 2011 at 7:57 Comment(4)
Can you please provide the code where you generate the search link? Is it jus a search_path? Do you use any gem for the search?Suffuse
Sorry I'm afraid I don't understand. What do you mean by search link? Searching is done via a form which is submitted to the searches_create_path via POST request.Leatherback
Did you solve this problem? I am experiencing very similar one? If yes please provide some clue. RegardsPenza
No I never got to the bottom of it. I moved on from that project.Leatherback
F
6

General Idea

You can fix this by editing the pagination partials to manually strip out the params from the url, then add the page param back. I know this is a hack, but it seems like the quickest way to fix this issue if pagination is broken (as it was for me).

I'm expanding this from the solution posted in the GitHub bug report for this issue.

You have to edit each of the 5 pagination link partials: _page.html.erb (by number), _first_page.html.erb and _last_page.html.erb, _prev_page.html.erb and _next_page.html.erb.

You can find the page number you want from the local variables made available in the partials: current_page, page, num_pages.

Specific Instructions

If you haven't already, generate the pagination partials in your app by running rails g kaminari:views default

Then edit the partials as follows:

#_page.html.erb
<%
 unless page.current?
   url = url.split('?')[0] + '?page=' + page.to_s
 end
%>

<span class="page<%= ' current' if page.current? %>">
  <%= link_to_unless page.current?, page, url, opts = {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} %>
</span>

# _first_page.html.erb
<span class="first">
  <% url = url.split('?')[0] + '?page=1' %>
  <%= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote %>
</span>

# _prev_page.html.erb
<span class="prev">
  <% url = url.split('?')[0] + '?page=' + (current_page.to_i - 1).to_s %>
  <%= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote %>
</span>

# _next_page.html.erb
<span class="next">
  <% url = url.split('?')[0] + '?page=' + (current_page.to_i + 1).to_s %>
  <%= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote %>
</span>

# _last_page.html.erb
<span class="last">
  <% url = url.split('?')[0] + '?page=' + num_pages.to_s %>
  <%= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} %>
</span>
Farfamed answered 21/9, 2011 at 16:17 Comment(5)
Anyone know how to fix the highlighting?Farfamed
An upboat for you. Shame we need to hack it like this, but got my app working with your code. (Not sure what Brendan's highlighting issue is; working fine for me.)Zavras
To add to the utility of this: I also need to keep the params but put them in the post data. You can grab the data from the right hand of the split, and add them to a :data => {:params => data} element, and rails ujs will happily serialize it for you on the post call!Hypoglycemia
kaminari: num_pages has been renamed to total_pagesYawp
I tried @Hypoglycemia what you suggested in order to keep the params, but my params get lost. Here is the line from my _last_page.html.erb with <% data = Rack::Utils.parse_query URI(url).query %> in order to get my save my params and here is my link to that page: <%= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, :remote => remote, :method => method, :data => { params: data } %>. Anyone can tell me what I'm doing wrong?Electro
C
9

If someone still has problems with pagination links, there is a fix here: Kaminari: Exclude basic form params from pagination links

Although, it does not work form me, as it was described in the commit description, there are still unwanted params in the link (:authenticity_token, :commit, :utf8, :_method), but you can exclude them by setting them to nil

For example:

paginate @books, params: {authenticity_token: nil, commit: nil, utf8: nil, action: nil}

Result:

<a href="/books?page=2">2</a>

OR

Controller:

def index
  # here search staff, messing our params hash
  @books = Books.all
  @pagination_params = normalize_pagination_params
end

private
def normalize_pagination_params
 params.inject({}) do |params_hash, p|
  unless p[0]=="controller"
    params_hash[p[0]] = nil
  end
  params_hash
 end
end

View:

paginate @books, params: @pagination_params
Coenesthesia answered 18/6, 2014 at 14:28 Comment(0)
F
6

General Idea

You can fix this by editing the pagination partials to manually strip out the params from the url, then add the page param back. I know this is a hack, but it seems like the quickest way to fix this issue if pagination is broken (as it was for me).

I'm expanding this from the solution posted in the GitHub bug report for this issue.

You have to edit each of the 5 pagination link partials: _page.html.erb (by number), _first_page.html.erb and _last_page.html.erb, _prev_page.html.erb and _next_page.html.erb.

You can find the page number you want from the local variables made available in the partials: current_page, page, num_pages.

Specific Instructions

If you haven't already, generate the pagination partials in your app by running rails g kaminari:views default

Then edit the partials as follows:

#_page.html.erb
<%
 unless page.current?
   url = url.split('?')[0] + '?page=' + page.to_s
 end
%>

<span class="page<%= ' current' if page.current? %>">
  <%= link_to_unless page.current?, page, url, opts = {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} %>
</span>

# _first_page.html.erb
<span class="first">
  <% url = url.split('?')[0] + '?page=1' %>
  <%= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote %>
</span>

# _prev_page.html.erb
<span class="prev">
  <% url = url.split('?')[0] + '?page=' + (current_page.to_i - 1).to_s %>
  <%= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote %>
</span>

# _next_page.html.erb
<span class="next">
  <% url = url.split('?')[0] + '?page=' + (current_page.to_i + 1).to_s %>
  <%= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote %>
</span>

# _last_page.html.erb
<span class="last">
  <% url = url.split('?')[0] + '?page=' + num_pages.to_s %>
  <%= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} %>
</span>
Farfamed answered 21/9, 2011 at 16:17 Comment(5)
Anyone know how to fix the highlighting?Farfamed
An upboat for you. Shame we need to hack it like this, but got my app working with your code. (Not sure what Brendan's highlighting issue is; working fine for me.)Zavras
To add to the utility of this: I also need to keep the params but put them in the post data. You can grab the data from the right hand of the split, and add them to a :data => {:params => data} element, and rails ujs will happily serialize it for you on the post call!Hypoglycemia
kaminari: num_pages has been renamed to total_pagesYawp
I tried @Hypoglycemia what you suggested in order to keep the params, but my params get lost. Here is the line from my _last_page.html.erb with <% data = Rack::Utils.parse_query URI(url).query %> in order to get my save my params and here is my link to that page: <%= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, :remote => remote, :method => method, :data => { params: data } %>. Anyone can tell me what I'm doing wrong?Electro
V
0

You could try cleaning params by keeping only the things you need and deleting everything else before displaying the search results.

To use post I think you missed a second step, where you have to override the kaminari link partials : https://github.com/amatsuda/kaminari/wiki/Kaminari-recipes

Volumed answered 1/7, 2011 at 10:17 Comment(0)
J
0

Old Post. Better solution.

If you are using kaminari for pagination for nested resources with ajax updates, you will find Kaminari attempts to build the url based on the current path, regardless of the params you specify, resulting in a routing error.

The cleanest solution is to use a wildcard route.

If your paginating comments for a post and have a comments controller with a create and show action, then:

In your routes:

match '*path/comments(/:page)' => 'comments#show'

And the pagination widget:

<%= paginate @comments, params: { controller: :comments }, remote: true %>
Joviality answered 15/5, 2013 at 22:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.