首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >带分页的Rails active_model_serializer

带分页的Rails active_model_serializer
EN

Stack Overflow用户
提问于 2014-04-09 04:40:40
回答 3查看 11.9K关注 0票数 19

我使用的是active_model_serializer。现在我想用分页来序列化一个对象,我应该在控制器中还是在序列化器中进行分页逻辑呢?

如果我选择在序列化程序中进行分页,我需要将page_number和per_page传递给序列化程序。我该怎么做呢?我的理解是序列化程序只接受模型对象。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-04-11 10:47:36

单机版解决方案

常规的序列化程序只关注单个项目-而不是分页列表。添加分页的最直接方法是在控制器中:

customers = Customer.page(params[:page])
respond_with customers, meta: {
  current_page: customers.current_page,
  next_page: customers.next_page,
  prev_page: customers.prev_page,
  total_pages: customers.total_pages,
  total_count: customers.total_count
}

可重用的解决方案

但是,如果您需要多个对象的分页逻辑,这就相当单调乏味。浏览active_model_serializers的文档时,您会发现一个用于序列化对象数组的ArraySerializer。我所做的是使用ArraySerializer创建pagination_serializer.rb,以自动为分页数组添加元标记:

# my_app/app/serializers/pagination_serializer.rb
class PaginationSerializer < ActiveModel::Serializer::ArraySerializer
  def initialize(object, options={})
    meta_key = options[:meta_key] || :meta
    options[meta_key] ||= {}
    options[meta_key][:pagination] = {
      current_page: object.current_page,
      next_page: object.next_page,
      prev_page: object.prev_page,
      total_pages: object.total_pages,
      total_count: object.total_count
    }
    super(object, options)
  end
end

PaginationSerializer添加到rails应用程序后,当您需要控制器中的分页元标记时,只需调用它即可:

customers = Customer.page(params[:page])
respond_with customers, serializer: PaginationSerializer

注意:我写这段代码是为了使用Kaminari作为分页器。但是,可以很容易地对其进行修改,以使用任何分页gem或自定义解决方案。

票数 45
EN

Stack Overflow用户

发布于 2020-04-19 04:04:52

2020更新:如果您使用json_api模式,active_model_serializer现在支持这一点,但如果您使用json模式,文档还会教您如何添加它。

文档在这里:https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/howto/add_pagination_links.md

下面我将解释如果您使用json_apijson适配器,如何获得所需的结果。检查您在ActiveModelSerializers.config.adapter上使用的是哪一个。

如果您正在使用JSON API适配器(您的ActiveModelSerializers.config.adapter = :json_api)

只要资源已分页并且您正在使用JsonApi适配器,分页链接就会自动包含在您的响应中。

如果您希望在响应中包含分页链接,请使用KaminariWillPaginate

Kaminari示例

#array
@posts = Kaminari.paginate_array([1, 2, 3]).page(3).per(1)
render json: @posts

#active_record
@posts = Post.page(3).per(1)
render json: @posts

WillPaginate示例

#array
@posts = [1,2,3].paginate(page: 3, per_page: 1)
render json: @posts

#active_record
@posts = Post.page(3).per_page(1)
render json: @posts
ActiveModelSerializers.config.adapter = :json_api

例如:

{
  "data": [
    {
      "type": "articles",
      "id": "3",
      "attributes": {
        "title": "JSON API paints my bikeshed!",
        "body": "The shortest article. Ever.",
        "created": "2015-05-22T14:56:29.000Z",
        "updated": "2015-05-22T14:56:28.000Z"
      }
    }
  ],
  "links": {
    "self": "http://example.com/articles?page[number]=3&page[size]=1",
    "first": "http://example.com/articles?page[number]=1&page[size]=1",
    "prev": "http://example.com/articles?page[number]=2&page[size]=1",
    "next": "http://example.com/articles?page[number]=4&page[size]=1",
    "last": "http://example.com/articles?page[number]=13&page[size]=1"
  }
}

ActiveModelSerializers分页依赖于具有current_pagetotal_pagessize方法的分页集合,例如KaminariWillPaginate都支持这些方法。

如果您正在使用JSON适配器(您的ActiveModelSerializers.config.adapter = :json)

如果您没有使用JSON适配器,则不会自动包含分页链接,但可以使用meta密钥来实现。

将此方法添加到您的基础API控制器。

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
  }
end

然后,在您的render方法上使用它。

render json: posts, meta: pagination_dict(posts)

例如。

{
  "posts": [
    {
      "id": 2,
      "title": "JSON API paints my bikeshed!",
      "body": "The shortest article. Ever."
    }
  ],
  "meta": {
    "current_page": 3,
    "next_page": 4,
    "prev_page": 2,
    "total_pages": 10,
    "total_count": 10
  }
}

如果您有一个在meta标记中添加分页信息的helper方法,您也可以获得相同的结果。例如,在您的操作中指定一个自定义序列化程序。

render json: @posts, each_serializer: PostPreviewSerializer, meta: meta_attributes(@posts)
#expects pagination!
def meta_attributes(collection, extra_meta = {})
  {
    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
  }.merge(extra_meta)
end

属性适配器

这个适配器不允许我们使用meta键,因为它不可能添加分页链接。

票数 6
EN

Stack Overflow用户

发布于 2020-01-30 15:08:30

https://github.com/x1wins/tutorial-rails-rest-api/blob/master/lib/pagination.rb

# /lib/pagination.rb
class Pagination
  def self.build_json object, param_page = {}
    ob_name = object.name.downcase.pluralize
    json = Hash.new
    json[ob_name] = ActiveModelSerializers::SerializableResource.new(object.to_a, param_page: param_page)
    json[:pagination] = {
        current_page: object.current_page,
        next_page: object.next_page,
        prev_page: object.prev_page,
        total_pages: object.total_pages,
        total_count: object.total_count
    }
    return json
  end
end

如何使用

#app/controller/posts_controller.rb
#post#index
render json: Pagination.build_json(@posts)

全源https://github.com/x1wins/tutorial-rails-rest-api

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22947721

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档