【问题标题】:Pagination Best Practices Ruby分页最佳实践 Ruby
【发布时间】:2019-01-25 07:47:47
【问题描述】:

所以我正在开发一个 Rails 应用程序,并且我正在对提要进行分页。当我这样做时,我想知道我是否以正确的方式进行操作,因为我的加载时间超过 1500 毫秒。我的代码是:

stories = Story.feed
@stories = Kaminari.paginate_array(stories).page(params[:page]).per(params[:pageSize])

我对此有几个问题:

  1. 我应该分页Story.feed,还是有什么方法 只返回一些我需要的故事?
  2. 这个加载时间正常吗?
  3. 我还可以做些什么来优化它

(另外,Story.feed 返回一个故事对象数组。代码在这里:

  def self.feed
    rawStories = Story.includes([:likes, :viewers, :user, :storyblocks]).all
    newFeaturedStories = rawStories.where(:featured => true).where(:updated_at.gte => (Date.today - 3)).desc(:created_at).entries
    normalStories = rawStories.not_in(:featured => true, :or => [:updated_at.gte => (Date.today - 3)]).desc(:created_at).entries
    newFeaturedStories.entries.concat(normalStories.entries)
  end

我正在使用 mongoid 和 mongodb

【问题讨论】:

    标签: ruby-on-rails ruby pagination kaminari


    【解决方案1】:

    问题是您从数组中的 db 获取所有提要,这需要很长时间。

    我建议你使用any_of查询from this great gem

    从那里开始:

    def self.feed_stories
      newFeaturedStories = Story.where(:featured => true).where(:updated_at.gte => (Date.today - 3.days))
      normalStories      = Story.not_in(:featured => true, :or => [:updated_at.gte => (Date.today - 3.days)])
      Story.includes([:likes, :viewers, :user, :storyblocks]).any_of(newFeaturedStories, normalStories).desc(:created_at)
    end
    

    然后分页:

    selected_stories = Story.feed_stories.per(page_size).page(page)
    

    不太明白你的entries 是什么,但现在得到它们。

    总结一下:做一个独特的分页数据库查询的想法。

    【讨论】:

    • 我收到此错误undefined method `inject' for #<Story:0x007faf703682e8>
    【解决方案2】:

    我怀疑当您在ActiveRecord::Relation 上调用Kaminari.paginate_array 时,它会导致整个结果集从数据库中获取并加载到内存中,类似于调用Model.all.to_a

    为了避免这种情况,我首先想办法将Story.feed 变成一个作用域,而不是一个类方法。从表面上看,它们看起来是一样的——差异很微妙,但很深刻。见Active Record scopes vs class methods

    接下来,放弃 paginate_array 转而使用链 Kaminari 的 page()per() 范围。

    例如(您的简化版):

    class Article < ActiveRecord::Base
    
      scope :featured,    -> { where(featured: true) }
      scope :last_3_days, -> { where(:updated_at.gte => (Date.today - 3)).desc(:created_at) }
      scope :feed,        -> { featured.last_3_days }
    

    然后简单地进行分页:

    Article.feed.per(page_size).page(page)
    

    这样做的最大优点是 Kaminari 可以链接到生成的 SQL 中插入正确的 LIMITOFFSET 子句,从而将返回的结果集的大小减少到只需要显示的内容,而不是返回每个匹配记录。

    【讨论】:

    • 这只会返回最近 3 天的精选故事。我需要的功能是让热门故事成为精选故事,无论日期如何,然后在其下方,其余故事按 created_at 日期排序
    • 就像我说的,这是您的简化版本。关键是使用per().page() 而不是concatpaginate_array(获取每个匹配的记录)。您必须将整个复合查询重写为范围(我只是假设这是可能的,我可能错了)。
    【解决方案3】:

    我认为 Will Paginate 会在这里帮助你 -> mislav/will_paginate。 从那里您可以简单地给您的控制器操作 .per_page(20) 例如,在 20 个对象之后(您可以定义对象,请参阅 wiki)会有分页

    【讨论】:

    • 他已经在使用 Kaminari gem,它的作用相同。
    猜你喜欢
    • 2012-12-02
    • 2012-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-25
    • 1970-01-01
    • 2019-05-03
    相关资源
    最近更新 更多