带分页的 Rails active_model_serializer

Posted

技术标签:

【中文标题】带分页的 Rails active_model_serializer【英文标题】:Rails active_model_serializer with pagination 【发布时间】:2014-05-21 18:43:05 【问题描述】:

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

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

【问题讨论】:

真的不清楚序列化在哪里。你在序列化什么?它与分页有什么关系?两者是完全分开的,我无法想象一个与另一个有什么关系。 @meagar 我正在尝试对相册进行序列化,我想在其中对照片进行分页。 你是不是想说你的结果是一个数组,而 will_paginate 不起作用? @StavrosSouvatzis 很抱歉造成混乱。我实际上正在使用 Kaminari 并且分页效果很好。我的问题是将分页逻辑放在哪里——我应该把它放在控制器中还是放在序列化器中。 @rmcshary 仅供参考,但 Link Rot 已进入。我认为此页面是等效的:github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/… 【参考方案1】:

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 适配器,则资源已分页。

如果您想在回复中添加分页链接,请使用Kaminari 或WillPaginate。

雷成例子
#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
将分页示例
#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 的分页集合,Kaminari 或 WillPaginate 都支持这些方法。

如果您使用的是 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 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
  

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

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 键,因为无法添加分页链接。

【讨论】:

这里的关键是 ActiveModelSerializers.config.adapter = :json_api 在您的 config/initializers/ams.rb 中的一个文件中。【参考方案2】:

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

【讨论】:

【参考方案3】:

一次性解决方案

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

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 或自定义解决方案一起使用。

【讨论】:

如果您有很多资源要分页,这是一种非常乏味且重复的方法。 @MarkMurphy 我更新了我的答案以展示如何使用 ArraySerializer 来清理代码并更加干燥 我希望分页键是***的,所以我还在PagedSerializer &lt; ActiveModel::ArraySerializer def as_json(*args) @options[:hash] = hash = @options[:unique_values] 上覆盖了#as_json = hash.merge!(@options[:pagination]) if @options.key?(:pagination) root = @options[:root] if root.present? hash.merge!(root => serializable_array) include_meta(hash) hash else serializable_array end end @LiDong 这取决于您拥有的active_model_serializers 版本。 0.10.0 和更高版本需要ActiveModel::Serializer::ArraySerializer - 旧版本需要ActiveModel::ArraySerializer 很好的解决方案,但不再需要,请参阅:github.com/rails-api/active_model_serializers/blob/master/docs/…

以上是关于带分页的 Rails active_model_serializer的主要内容,如果未能解决你的问题,请参考以下文章

Oracle11g 带分页的选择查询

带分页的 Ajax 搜索 [Laravel]

带分页的sql语句

使用带分页的php进行高级搜索?

一个类别和带分页的可多选表格的实现方案

带分页的Wordpress自定义循环