will_paginate JSON support?
Asked Answered
D

6

19

I wonder if anyone could please tell me if will_paginate can support JSON out of the box or if this has to be hacked?

I would like to add page data to the JSON responses while will_paginate manages pagination.

Docent answered 15/1, 2011 at 10:54 Comment(0)
F
47

Something in the lines of:

@posts = Post.paginate :page => params[:page]

respond_to do |format|
  format.json {
    render :json => {
      :current_page => @posts.current_page,
      :per_page => @posts.per_page,
      :total_entries => @posts.total_entries,
      :entries => @posts
    }
  }
end

Once you figure out what format you want, you can always define a to_json method on a WillPaginate::Collection.

Firooc answered 16/1, 2011 at 5:35 Comment(3)
yes that is what i am wanting to do, now i know how it works it probably returns what i need by rendering straight to JSON, however, been able to change the format like this is useful.Docent
check out the GitHub API docs[1] for a much better way of encoding pagination in your response (hint: put it in the headers) [1]: developer.github.com/v3/#paginationLaughable
How did you find these methods? They're not listed in the will_paginate wiki.Slippage
J
10

Adding Pagination to an API

I found an easy solution to API Json Response Pagination with will_pagination.

start by creating a class method in ApplicationController that will create an after_filter that will set the pagination meta-data in the response headers:

application_controller.rb

class ApplicationController < ActionController::Base

  protected
  def self.set_pagination_headers(name, options = {})
    after_filter(options) do |controller|
      results = instance_variable_get("@#{name}")
      headers["X-Pagination"] = {
        total: results.total_entries,
        total_pages: results.total_pages,
        first_page: results.current_page == 1,
        last_page: results.next_page.blank?,
        previous_page: results.previous_page,
        next_page: results.next_page,
        out_of_bounds: results.out_of_bounds?,
        offset: results.offset
      }.to_json
    end
  end

end

Then in the controller we want to add pagination headers we can call it like such:

widgets_controller.rb

class Api::V1::WidgetsController < Api::V1::BaseController
  set_pagination_headers :widgets, only: [:index]

  def index
    @widgets = Widget.all.paginate(params).order("created_at desc")
    respond_with @widgets
  end

end

response headers that look like this

> Cache-Control:max-age=0, private, must-revalidate
> Connection:keep-alive Content-Type:application/json; charset=utf-8
> Etag:"fe70f7bae4c6e5cdea7867aa7fc0c7b4"
> X-Pagination:{"total":14,"total_pages":1,"first_page":true,"last_page":true,"previous_page":null,"next_page":null,"out_of_bounds":false,"offset":0}
> Server:thin 1.3.1 codename Triple Espresso
> Set-Cookie:_widgets_session=BAh7CEkiD3Nlc3Npb25faWQGOgZFRkkiJTAzYjVlNzkwZTIyNzU4YTYwMDU0M2MwOTQ2ZWI3YWU2BjsAVEkiDWxhc3RfdXJsBjsARkkiM2h0dHA6Ly9tYWluYW5kbWUtc3RhZ2luZy5oZXJva3VhcHAuY29tL3VzZXJzLzEGOwBGSSIQX2NzcmZfdG9rZW4GOwBGSSIxdjd0SEp6cVhKamh5YTh1cnBUdmpBb0w5aVA0bS9QTEdON3g1UlFUYnBkND0GOwBG--71b3a24c216a414d8db04f312b5300c818e6bba4;
> path=/; HttpOnly Transfer-Encoding:Identity
> X-Request-Id:61b383ade49cba8b24a715a453ed6e1f X-Runtime:0.191485
> X-Ua-Compatible:IE=Edge,chrome=1

Source -Adding Pagination to an API

Joaniejoann answered 17/9, 2015 at 12:35 Comment(1)
This is great pagination for an API. Don't modify the returned data, place the pagination information in the headers. Super clean solution, plays nice with others like Angular who wants an array of results back for an index/list/query.Andrea
I
3

This one helps me:

Add this method to your base API controller.

def pagination_dict(collection)
  {
    current_page: collection.current_page,
    next_page: collection.next_page,
    prev_page: collection.prev_page, # use collection.previous_page when using will_paginate
    total_pages: collection.total_pages,
    total_count: collection.total_count # use collection.total_entries when using will_paginate
  }
end

Then, use it on your render method.

render json: posts, meta: pagination_dict(posts)
Ironsmith answered 24/4, 2017 at 18:56 Comment(2)
this is a dead link.Trinitrotoluene
thank you - i removed the url - but my snipped works.Ironsmith
J
2

The easiest solution

  def index
    @posts =  Post.all.paginate(:page => params[:page], :per_page => 4)
    render :json => @posts.to_json(:methods => [:image_url])
  end

You just need to add gem 'will_paginate'

It works for me.

Joaniejoann answered 17/9, 2015 at 13:58 Comment(0)
S
1

will_paginate just gets the records back in a sliced manner. So it just gets an array from your database.

When you render as json, that's rails going over the array of objects and calling as_json on them.

So yes, you can will_paginate rendering out as json.

Subantarctic answered 15/1, 2011 at 14:20 Comment(3)
But I guess i'll have to hack it so it includes the total number of pages in the JSON response along with the paginate data .Docent
that's all in the response from Model.paginate -- so you'll just need to look for it in the json response.Subantarctic
I'll also look into that. @Firooc provided and example of what i was looking for, however, I can see that just rendering the standard output as JSON should also contain the information that i need.Docent
G
0

Gem: will_paginate, version 3.1.8

  def pagination_meta(collection)
    {
      current_page: collection.current_page,
      next_page: collection.next_page,
      prev_page: collection.previous_page,
      total_page: collection.total_pages,
      total_count: collection.total_entries,
    } if collection.present?
  end
Gatefold answered 25/5, 2021 at 8:50 Comment(2)
Can you add a reference link to documentation or example of how to use it?Parapodium
github.com/mislav/will_paginate/wiki.Gatefold

© 2022 - 2024 — McMap. All rights reserved.