How do I paginate a hash of arrays using the Kaminari (or will_paginate) gem
Asked Answered
N

2

6

I've managed to find a workaround to this now. The index action now has an "order" clause before the call to page and the meals are then sorted and grouped by date. The hackey bit next: @total_pages and @pages are used in the view to provide pagination links as the built-in helper for this does not work with the Hash of arrays as returned by @meals. It works (kind of) but it is hackey. Moving the view stuff into a helper would definitely help clean it up, which is my next step.

def index
  @meals = Meal.order('date DESC').page(params[:page]).text_search(params[:query]).sort_by(&:date).reverse.group_by(&:date)
  @total_pages = (Meal.all.size / 7.to_f).ceil
  @pages = (1..@total_pages).to_a 
respond_to do |format|
  format.html # index.html.erb
  format.json { render json: @meals }
end

end

I really need help on this - it's been driving me mad for a couple of days. I am trying to paginate a hash of arrays. I have tried both will_paginate and Kaminari, but cannot find a way to paginate the resulting hash.

I'm running Rails 3.2.6, Ruby 1.9.3 and PostgreSQL 9.1.3 is doing the searching...

In my controller (and using Kaminari) I have:

def index
  @meals = Meal.text_search(params[:query]).sort_by(&:date).reverse.group_by(&:date).page(params[:page])
respond_to do |format|
  format.html # index.html.erb
  format.json { render json: @meals }
  end
end

And in my model I have the following search:

def self.text_search(query)
  if query.present?
    where("description @@ :q or meal_time @@ :q", q: query)
  else
    scoped
  end
end 

And in my view template:

<div class="container">
  <div class="row">
<%= form_tag meals_path, method: :get, :class => "well form-search" do %>
  <%= text_field_tag :query, params[:query], 
                     :class => "span3" %>
  <%= submit_tag "Search", name: nil, :class => "btn" %>
    <% if current_user %>
      <p class="pull-right"> 
    <%= link_to "Add a meal",
                new_meal_path,
                :class => 'btn btn-success' %>
    </p>
    <% else %>
    <% end %>
<% end %>       
</div>
<table class="table table-striped">
<tbody>
  <% @meals.each do |date, meals| %>
  <tr> 
    <td>
      <h2><%= date.to_s(:day_of_month) %></h2>
      <h6><%= date.to_s(:date_and_month) %></h6>
      <p><span class="badge badge-warning"><%= pluralize(meals.size, "meal") %></span></p>
    </td>
    <% meals.each do |meal| %>
      <td>
        <p>
          <strong>
            <%= meal.consumed_at.to_s(:just_the_time)%> 
            <%= meal.meal_time %> &#8212; 
            <%= meal.description %>
          </strong>
        </p>
        <%= link_to "Ingredients", meal_path(meal) %>
      </td>
      <% end %>
    </tr>
  <% end %>
</tbody>
</table> 
</div>
<%= paginate @meals %>  

This returns the following error:

NoMethodError in MealsController#index

undefined method `page' for Hash

Any help would be gratefully received!

Neumark answered 18/7, 2012 at 22:51 Comment(4)
I don't know anything about Ruby, but don't you usually paginate in the search function, not afterwards? I mean like this you would be getting ALL results, and then paginate in the hash! In the text_search part... Shouldn't there be "skip" and "limit" commands?Nymphalid
@Nymphalid - thanks for the help. I've managed to find a (bit of a hack) way around this that will do for now!Neumark
Could you post the work around??Neckcloth
@stevanity Apologies - I should have posted earlier, but my hack (that I thought worked) in fact did not work after all. Perhaps try the solution posted by Space Monkey.Neumark
A
4
Kaminari.paginate_array(ARRAY_OBJECT).page(params[:page]).per(50)
Arabia answered 12/12, 2012 at 11:4 Comment(0)
M
1

This is my solution after a while researching around if you have to use will_paginate (Kaminari is more flexible and easier to use)

  current_page = params[:page] || 1
  per_page = params[:per_page] || 20
  length = @data.length

  @data = WillPaginate::Collection.create(current_page, per_page, length) do |pager|
    pager.replace @data[pager.offset, pager.per_page].to_a
  end

After running these codes, @data will the same as an ActiveRecord object with will_paginate paging:

  • @data is an array of hash

  • <%= will_paginate(@data) %> is the code to show paging menu in view

Hope this help others who have the same question.

Multiplier answered 21/11, 2013 at 4:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.