我一直在寻找最好的方法,这段时间用平庸的结果做到这一点,所以我决定在这里问。
场景如下:我有三个模型,Task,User和Comment,基本上是这样的:
class Task < ActiveRecord::Base
belongs_to :user
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :task
end
class User < ActiveRecord::Base
has_many :tasks
has_many :comments
end
我正在尝试输出一个任务列表(让我们说这个问题的最后10个),以及每个任务的相关最后评论,以及可能的查询次数最少。
谢谢
更新:我结合了Blue Smith和harigopal的解决方案,所以解决方案如下:
class Task < ActiveRecord::Base
belongs_to :user
has_many :comments
has_one :last_comment, -> { order 'created_at' }, class_name: "Comment"
end
然后获取这样的评论:
tasks = Task.joins(last_comment: :user)
.includes(last_comment: :user)
.order('tasks.created_at DESC').limit(10).load
产生只有一个查询,这正是我想要的!谢谢!
答案 0 :(得分:2)
您必须加入这些表,然后急切加载数据以最大限度地减少查询次数。
例如:
tasks = Task.joins(comments: :user)
.includes(comments: :user)
.order('tasks.created_at DESC')
.limit(10).load
comments = tasks.first.comments # No query, eager-loaded
user = comments.first.user # No query, eager-loaded
这应该会将查询数量减少到只有一个(非常复杂的一个),因此您必须确保您的索引符合要求! :-D
关于组合联接和包含的官方文档很模糊,但应该有所帮助:http://guides.rubyonrails.org/active_record_querying.html#joining-multiple-associations
修改强>
这是一个演示应用程序,其模型与您使用上述方法执行eager-loading相同。它使用两个查询来加载数据。启动应用程序以查看其运行情况。
https://github.com/harigopal/activerecord-join-eager-loading
答案 1 :(得分:1)
您可以尝试以下方式:
class Task
scope :recent, order('created_at desc')
scope :last, lambda{|n| limit: n }
end
现在您拥有可重复使用的范围:
Task.recent.last(10)
我猜你想输出给定用户的最后10个任务(假设当前登录的用户)。
current_user.tasks.recent.last(10).includes(comments: user)
答案 2 :(得分:1)
你可以试试这个:
class Task < ActiveRecord::Base
belongs_to :user
has_many :comments
has_one :last_comment, :class_name => 'Comment', :order => 'comments.created_at DESC'
end
@tasks = Task.limit(10).includes(:last_comment => :user)
last_comment
是一个“虚拟”关联,只加载一条Comment
条记录。这种方法的优点是它将使用更少的内存(因为只加载一个Comment
和一个相关的User
)。如果使用includes(comments: user)
,它可能会消耗大量内存(如果有很多注释:)。