Search code examples
jqueryruby-on-railsajaxkaminari

Pagination does not work after Ajax call in Rails


I am using plugin Kaminari for pagination. I am Ajaxifing my application and I encountered a problem. I have a form with paginated data plus form for filtering data (both via Ajax). At start pagination works good, and the url's for particular pages are '/admin/rooms?page=X'. After ajax filtering those url's change for '/admin/rooms/filter?page=X'. I can specify the action to trigger when paginating by:

<%= paginate @rooms, :params => {:controller => 'rooms', :action => 'index'}, :remote => true %>

but then variable @rooms gets resetted in index and I paginate unfiltered data again.

Any ideas how could I fix it?

Here's some code

  • rooms_controller.rb:

    class Admin::RoomsController < AdminController
    def index
            @rooms = Room.all
            @rooms = Kaminari.paginate_array(@rooms).page(params[:page]).per(5)
            @filter_values = [['Room number', 'room_number'], ['Person count', 'person_count'], ['Room class', 'room_class']]
    end
    
    def filter
            case params[:filter_by]
            when 'room_number'
                    @rooms = Room.find(:all, :conditions => ["CAST(room_number AS VARCHAR) LIKE ?", "#{params[:filter_value]}%"])
            when 'person_count'
                    @rooms = Room.find(:all, :conditions => ["person_count LIKE ?", "#{params[:filter_value]}%"])
            else
                    @rooms = Room.joins(:room_class).where("lower(class_name) LIKE '#{params[:filter_value]}%'")
            end
    
            @rooms = Kaminari.paginate_array(@rooms).page(params[:page]).per(5)
            respond_to do |format|
                    format.html { redirect_to admin_rooms_path }
                    format.js
            end
    end
    
  • index.html.erb:

    <%= label_tag 'Filter:  ' %>
    <%= form_tag(filter_admin_rooms_path, :remote => true) do %>
            <%= select_tag :filter_by, options_for_select(@filter_values) %>
            <%= text_field_tag :filter_value %>
            <%= submit_tag 'Filter', :disable_with => 'Filtering..' %>
    <% end %>
    
    ...
    
    <div id="rooms_list">
            <%= render 'admin/rooms/shared/rooms_list' %>
    </div>
    
  • _rooms_list.html.erb:

    <div id="paginator">
            <%= paginate @rooms, :remote => true %>
    </div>
    <table class="table_listing" style="width: 60%">
            ...
    </table>
    

Solution

  • Problem solved by passing parameters again to index and forcing paginate to route to 'rooms#index', not the current page (not visible cause of Ajax though).

    • _rooms_list.html.erb:

      <%= paginate @rooms, :params => {:controller => 'rooms', :action => 'index'}, :remote => true %>
      

    Parametrs are passed to index by GET from the present params variable.

    • rooms_controller.rb:

      def index
              if params[:filter_value].nil?
                      @rooms = Room.all
              else
                      @rooms = test_filter(params[:filter_value])
              end
      
              @rooms = Kaminari.paginate_array(@rooms).page(params[:page]).per(5)
              @errors = flash[:errors] || []
              @filter_values = [['Room number', 'room_number'], ['Person count', 'person_count'], ['Room class', 'room_class']]
      end
      
      def filter
              case params[:filter_by]
              when 'room_number'
                      @rooms = Room.find(:all, :conditions => ["CAST(room_number AS VARCHAR) LIKE ?", "#{params[:filter_value]}%"])
              when 'person_count'
                      @rooms = Room.find(:all, :conditions => ["person_count LIKE ?", "#{params[:filter_value]}%"])
              else
                      @rooms = Room.joins(:room_class).where("lower(class_name) LIKE '#{params[:filter_value]}%'")
              end
      
              @rooms = Kaminari.paginate_array(@rooms).page(params[:page]).per(5)
              params[:authenticity_token] = nil
              params[:commit] = nil
      
              respond_to do |format|
                      format.html { redirect_to admin_rooms_path }
                      format.js
              end
      end
      
      def test_filter(val)
              rooms = Room.find(:all, :conditions => ["CAST(room_number AS VARCHAR) LIKE ?", "#{val}%"])
              rooms
      end
      

    test_filter is to remove/rename of course. I nil some parameter that I think shouldn't be passed in params to the next page when paginate.