Rails will_paginate 分页问题

dgy1126 · 2014年10月31日 · 最后由 hupengxing 回复于 2014年11月03日 · 3133 次阅读

网站使用 will_pagination 进行分页,controller 中的语句如下: @value = array.paginate(:per_page => per_page, :page => page, :total_entries => total_length)

我将第 40 页的 10 条数据存到 array 中,参数 per_page = 10, page = 40, total_length = 1000,这种情况下网页显示为空,此时@value的值为 nil. 如果我将前 40 页的所有 400 条数据保存在 array 中,网页则可以正常显示。

问题如下: 1 如果我想显示第 40 页的数据,我是否需要把前 40 页的数据全部取出存到 array 中呢?如果不需要,该怎么调用函数呢?

2 若不能的话,如果页面共有 100000 页,但是只显示最后一页,这样也需要取出全部数据,效率是否会过低?

谢谢!

不要用 array, 用 relation, Active Recorder 查询是 relation, 再与 will_paginate 连用还是 relation. 最后生成的 sql 语句才会反回真正的数据. 所以你的第二个问题不成立。

#1 楼 @itomato 1 您的意思是说如果用 relation,那么生成的 SQL 语句就只会取一页的数据? 2 现在的场景只能采用 array,因为数据是调用 API 取得的,API 返回的就是数组。是否有方法能将 array 转化为 relation?

谢谢!

#2 楼 @dgy1126 完全可以。

@value= Model.where(:id=>array.map{|element| element.id})

#3 楼 @gyorou 您好,我的问题不单单是要把 array 转化为 relation。

我的问题是要显示第 40 页的 10 条数据,而我从后台取到的数据就是一个长度为 10 的对象数组,数组中的数据就是要显示在第 40 页的 10 个值。

此时没有 Model,如何使用 will_paginate 和这个数组将正确的数据显示在第 40 页上?

·@value = array.paginate(:per_page => per_page, :page => page, :total_entries => total_length)· 简单这么用显示的第 40 页的数据为空。

谢谢!

这个问题难道不该是 api 来解决吗?

同意 @small_fish__ 的说法。数据既然是 api 请求,那么应该是通过修改 api 请求的参数来获取分页数据

再看 will_paginate, 在 github 上说

will_paginate is a pagination library that integrates with Ruby on Rails, Sinatra, Merb, DataMapper and Sequel

是直接对数据库进行 SQL 查询来实现分页

#5 楼 @small_fish__ api 返回的就是一页的 10 条数据,问题是前端如何使用这一页的数据显示在第 40 页上。

#6 楼 @JIAZHEN API 返回的确实是 10 条数据,但问题是没法将这 10 条数据显示在第 40 页上。

问题具体描述如下:

·@value = array.paginate(:per_page => per_page, :page => page, :total_entries => total_length)·

我将第 40 页的 10 条数据存到 array 中,参数 per_page = 10, page = 40, total_length = 1000,这种情况下网页显示第 40 页数据为空,因为此时@value的值为 nil. 如果我将前 40 页的所有 400 条数据保存在 array 中,网页则可以正常显示第 40 页数据。

谢谢!

@dgy1126 查看了一下will_pagnate的代码 (https://github.com/mislav/will_paginate/blob/623e9c5390998a2aca283bca28009f7d479d5f0f/lib/will_paginate/array.rb#L29)

WillPaginate::Collection.create(page, per_page, total) do |pager|
  pager.replace self[pager.offset, pager.per_page].to_a
end

因为当前 array 的 size 只有 10,但是你要把它 replace 从 index 40 - 50,所以返回 nil

irb(main):014:0> array, another_array = [1,2,3], [3,4,5]
=> [[1, 2, 3], [3, 4, 5]]
irb(main):015:0> array.replace another_array[40..50].to_a
=> []

之前说的由 api 处理,意思是在程序的 archtecture 层面上你目前的实现方式不是很好,IMO

#9 楼 @JIAZHEN 确实,我之前也想过办法,想用这 10 条数据显示到第 40 页。我的方案是在这 10 条数据之前插入 index 1 - 39 页的空值,即 39 * 10 = 390 个空值。这样 array 的 size 就可以满足将这 10 条数据显示到第 40 页的需求。

但是如果需要显示第 1000 页,就需要插入 1000 * 10 = 10000 个空值,这样效率太低。

1 您说 architecture 层面的实现方式不好,意思是否是说 API 返回一个长度为 10 的 array 的方式不好呢?

2 在采用 API 返回数据的情况下,您有什么好的方案来解决这个问题吗?

@dgy1126

  1. API 返回 array 可以。但是不必生硬地使用will_paginate,它可能不是一个适合的 gem
  2. 从架构方面讲,因为你的 rails 不能直接访问 DB,数据是从 API 来的。为什么不能直接显示 array? 你们需要的分页应该是 api pagination. FYI - https://github.com/davidcelis/api-pagination
  3. 更推荐你们实现自己的 API 分页,Keep it simple

#7 楼 @dgy1126 将 page=40 传给 api,让 api 做这个事情~

#10 楼 @dgy1126 我想你要的也就是页面上分页的实现吧,后台数据听你这意思是已经支持分页的查找了,取回的都是分页的数据,那何必一定要用 will_paginate 呢,你可以自己实现一个 view helper 来做分页的事情嘛,controller 中都不需要对你的 array 做什么操作

没理解,为什么不能直接从 API 取第 40 页的数据呢?

需要 登录 后方可回复, 如果你还没有账号请 注册新账号