ruby-on-railswill-paginatepg-search

Ruby on Rails: getting 404 not found error, when going to next page after search, using pg_search and will_paginate


I'm facing a strange error, where going to next page after search will cause 404 not found error. But the pagination works well if I don't search.

routes.rb

resources :activities do
  post :search, on: :collection
end

match "/403", to: "errors#error_403", via: :all
match "/404", to: "errors#error_404", via: :all
match "/422", to: "errors#error_422", via: :all
match "/500", to: "errors#error_500", via: :all

get :ie_warning, to: 'errors#ie_warning'
get :javascript_warning, to: 'errors#javascript_warning'
get :pwreset, to: "pages#pwreset"
get :activities, to: "activities#index"
get :home, to: "pages#home"
root to: "pages#home"

controller.rb

@@page_size = 3
# GET /activities
def index
  @activities = Activity.paginate(:page => params[:page], :per_page => @@page_size)
end

# POST /products/search
def search
  if params[:search][:title].present?
    @activities = Activity.search_activities(params[:search][:title]).paginate(:page => params[:page], :per_page => @@page_size)
    render :index
  else
    @activities = Activity.paginate(:page => params[:page], :per_page => @@page_size)
  end

end

html.haml

- @activities.each do |activity|
.row
  .col-md-8
    = link_to activity.title, activity
  .col-md-2
    %p= activity.publisher
  .col-md-2
    %p= activity.created_at.to_date

.force-to-bottom
  .text-center
    = will_paginate @activities


= simple_form_for :search, url: search_activities_path, method: :post do |f|

  .form-inline
    = f.input :title, label: false, placeholder: 'search...'

    = button_tag(type: 'submit', class: "btn btn-primary") do
      %span.glyphicon.glyphicon-search{"aria-hidden" => "true"}

    %span.glyphicon.glyphicon-remove{"aria-hidden" => "true"}
    = link_to 'clear filter', activities_path

error message

Started GET "/activities/search?page=2" for ::1 at 2018-04-16 04:39:57 +0100
Processing by ActivitiesController#show as HTML
Parameters: {"page"=>"2", "id"=>"search"}
Activity Load (17.9ms)  SELECT  "activities".* FROM "activities" WHERE "activities"."id" = $1 LIMIT $2  [["id", 0], ["LIMIT", 1]]
Rendering errors/error_404.html.haml within layouts/application
Haml::TempleEngine: Option :ugly is invalid
Rendered errors/error_404.html.haml within layouts/application (6.2ms)
Haml::TempleEngine: Option :ugly is invalid
Haml::TempleEngine: Option :ugly is invalid
Rendered layouts/_environment_notice.html.haml (2.0ms)
Completed 404 Not Found in 245ms (Views: 162.2ms | ActiveRecord: 74.7ms)

any one can help please, I still really don't know what is going on with that error after a few hours of research


Solution

  • When you search the parameters are submitted via the POST method (method: :post). When you click next page you request the page via GET, however the browser does not send the search parameters via GET and there is no route get :search so the show action is used instead leading to the 404 page.

    While it may be possible to make will_paginate use POST it is not recommended.

    Cf. https://github.com/mislav/will_paginate/wiki/Simple-search :

    When you create a search form, make sure its method is GET

    <% form_tag request.path, :method => 'get' do %>
      <% content_tag :label do %>
        Search term:
        <%= text_field_tag :search, params[:search] %>
      <% end %>
    <% end %>
    

    If your form's action is POST (or any other HTTP method) then the search term won't be applied to subsequent page links. In other words, when you follow the "Next page" or any other page link, the search parameter(s) would be lost.

    Search forms that post with GET are better practice, anyway. One of immediate benefits is that users are able to bookmark search results. Caching is another benefit: browsers, proxies, etc. are happy to cache content that was a result of a GET request.