【问题标题】:how to paginate records from multiple models? (do I need a polymorphic join?)如何对来自多个模型的记录进行分页? (我需要多态连接吗?)
【发布时间】:2011-12-18 22:56:34
【问题描述】:

经过相当多的搜索,我还是有点迷茫。还有一些其他类似的问题涉及对多个模型进行分页,但它们要么没有答案,要么分别对每个模型进行分页。

我需要一次对帐户的所有记录进行分页。

class Account
  :has_many :emails
  :has_many :tasks
  :has_many :notes
end

所以,我想找到 30 个最近的“事物”,无论它们是什么。使用当前的分页解决方案,这甚至可能吗?

喜欢使用急切加载和 Kaminari 或 will_paginate 的某种组合?


或者,我应该首先设置所有这些东西的多态连接,称为项目。然后对最近的 30 个项目进行分页,然后查找这些项目的关联记录。

如果是这样,我不确定该代码应该是什么样子。有什么建议吗?


哪种方式更好? (甚至可能)

Rails 3.1、Ruby 1.9.2、应用未投入生产。

【问题讨论】:

  • 使用 will_paginate,这应该会有所帮助:stackoverflow.com/questions/1465949/…
  • 谢谢。但是,这不是我想要的。
  • 认为“对一组数据行进行分页”而不是对一个数据库表的多行进行分页可能会有所帮助。数据来自多少个模型并不重要。您可能还希望查看 kaminiri 以了解它是否更好地满足您的需求。
  • 谢谢@MichaelDurrant,但我不确定如何“通过一组数据行”进行分页。我查看了 Kaminari,但无法确定它是否同时适用于多个表。我想我想知道如何当它可以是模型的任意组合时,你怎么能用 SQL 获取 30 个最新的。绝对没有 sql 专家,但是有没有办法在没有某种 n+1 查询的情况下将查询限制为 30?

标签: ruby-on-rails ruby-on-rails-3 ruby-on-rails-3.1 will-paginate kaminari


【解决方案1】:

好问题...我不确定“好的”解决方案,但您可以在 ruby​​ 中做一个 hacky 解决方案:

您需要先取出每种“事物”中最新的 30 个,并将它们放入一个数组中,以 created_at 为索引,然后按 created_at 对该数组进行排序并取出前 30 个。

完全未重构的开始可能是这样的:

emails = Account.emails.all(:limit => 30, :order => :created_at)
tasks = Account.tasks.all(:limit => 30, :order => :created_at)
notes = Account.notes.all(:limit => 30, :order => :created_at)
thing_array = (emails + tasks + notes).map {|thing| [thing.created_at, thing] }
# sort by the first item of each array (== the date)
thing_array_sorted = thing_array.sort_by {|a,b| a[0] <=> b[0] }
# then just grab the top thirty
things_to_show = thing_array_sorted.slice(0,30)

注意:未经测试,可能充满了错误... ;)

【讨论】:

  • 感谢您的回复。但是,这样做的性能太差了,每次都必须获取 60 条额外的记录。然后必须跟踪每个呈现了多少。此外,您的 things_array 可以重构为:(emails + tasks + notes).sort_by(&amp;:updated_at).take(30)
  • 需要反向获取最新的:(emails + tasks + notes).sort_by(&amp;:updated_at).reverse.take(30)
  • 是的 - 绝对性能不佳......正如我所说 - 只是一个 hacky 解决方案 :)
【解决方案2】:

与 will_paginate :

@records = #do your work and fetch array of records you want to paginate ( various types )

然后执行以下操作:

current_page = params[:page] || 1
per_page = 10
@records = WillPaginate::Collection.create(current_page, per_page, records.size) do   |pager|
pager.replace(@records)
end

那么在你看来:

<%=will_paginate @records%>

【讨论】:

    【解决方案3】:
    emails = account.emails
    tasks = account.tasks
    notes = account.notes
    
    @records = [emails + tasks + notes].flatten.sort_by(&:updated_at).reverse
    
    @records = WillPaginate::Collection.create(params[:page] || 1, 30, @records.size) do |pager|
      pager.replace(@records)
    end
    

    就是这样... :)

    【讨论】:

      猜你喜欢
      • 2011-10-22
      • 2013-09-30
      • 1970-01-01
      • 2015-05-27
      • 2018-08-18
      • 2016-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多