如何对来自多个模型的记录进行分页? (我需要多态连接吗?)
Posted
技术标签:
【中文标题】如何对来自多个模型的记录进行分页? (我需要多态连接吗?)【英文标题】: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,这应该会有所帮助:***.com/questions/1465949/… 谢谢。但是,这不是我想要的。 认为“对一组数据行进行分页”而不是对一个数据库表的多行进行分页可能会有所帮助。数据来自多少个模型并不重要。您可能还希望查看 kaminiri 以了解它是否更好地满足您的需求。 谢谢@MichaelDurrant,但我不确定如何“通过一组数据行”进行分页。我查看了 Kaminari,但无法确定它是否同时适用于多个表。我想我想知道如何当它可以是模型的任意组合时,你怎么能用 SQL 获取 30 个最新的。绝对没有 sql 专家,但是有没有办法在没有某种 n+1 查询的情况下将查询限制为 30? 【参考方案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(&:updated_at).take(30)
需要反向获取最新的:(emails + tasks + notes).sort_by(&: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
就是这样... :)
【讨论】:
以上是关于如何对来自多个模型的记录进行分页? (我需要多态连接吗?)的主要内容,如果未能解决你的问题,请参考以下文章