Rails:通过has_many关联的最后一个元素对模型进行排序

时间:2016-02-22 19:48:09

标签: ruby-on-rails ruby join activerecord rails-activerecord

我有两个模型:UserMessage,它们通过has_many关系连接起来。我想获得一个users列表,按照上一条消息的时间戳排序。

class User < ActiveRecord::Base
  has_many :messages
end
class Message < ActiveRecord::Base
  belongs_to :user
end

当我这样做时:

@users = User.includes(:messages).order('messages.created_at DESC').limit(5)

似乎订购消息,抓取最新的5条消息,然后返回与这些消息相关联的用户。所以用户数量可以少于5.我想确保我得到5个用户。

我希望查询获取每个请求的最新消息,订购最后的消息,然后返回带有最新消息的用户。所以我想要这样的东西:

@users = User.includes(:messages).order( <messages.last.created_at DESC> )

理想情况下,解决方案会对数据库进行排序,因为我想使用paginate。如果它与我使用Postgres相关。

3 个答案:

答案 0 :(得分:6)

我可能会优先考虑phoet提到的向用户添加属性的解决方案,例如last_message_posted_at,并使用touch: true在消息创建时更新该属性。这简化了在需要提取用户列表时必须执行的查询。这也为您的应用程序提供了更具可读性(IMO)的链:

@users = User.all.order(:last_message_posted_at)
=> "SELECT \"users\".* FROM \"users\" ORDER BY \"users\".\"last_message_posted_at\" ASC"

这也允许您为用户模型添加一个漂亮而简单的范围

scope: :by_recent_message, ->{ order(:last_message_posted_at) }
User.by_recent_message.limit(5)

它还取决于使用此@users范围的时间和频率。对于我来说,在每次拉出用户列表时,比在复杂的SQL查询中添加几毫秒的邮件时间更好。

- 为那些不熟悉触控语法的人编辑

触摸文档:http://apidock.com/rails/v4.2.1/ActiveRecord/Persistence/touch

class User < ActiveRecord::Base
  has_many :messages
end
class Message < ActiveRecord::Base
  belongs_to :user, touch: true
end

然后进行查询(给最近最后一条消息的用户):

@user =  User.includes(:messages).order(updated_at: :desc )

答案 1 :(得分:0)

你可以尝试一下

Message.group(:user_id).joins(:users).order('max(messages.created_at) desc')

答案 2 :(得分:0)

您可以使用左连接而不是包含

@users = User.joins("LEFT JOIN messages on messages.user_id = users.id").order('messages.created_at').limit(5)