新手问题 类似 “按照最新发布文章时间排序的用户列表” 的优雅的实现方法

blueplanet · 2015年05月01日 · 最后由 blueplanet 回复于 2015年06月16日 · 1844 次阅读

前提

class User < AR
  has_many :posts
end

class Post < AR
  belongs_to :user
end

问题

  • 想要实现用户的列表,按照用户最新发布的文章的时间排序
  • 用数据举例来说,如果有下列数据的话,希望显示的顺序是user2 ; user1
user1
  post1 2015-03-01 00:00:00
  post2 2015-03-02 00:00:00
user2
  post11 2015-03-03 00:00:00

目前的实现方法

scope :order_list, -> {
    select(<<-EOS
      users.*,
      (SELECT MAX(created_at) FROM posts WHERE users.id = posts.user_id) max_created_at
    EOS
      ).joins(:posts).
      order('max_created_at DESC').
      uniq
}

虽然使用直接嵌套 SQL 的方法实现了,总觉得应该有更优雅的实现方法,希望各路高手指教一下,谢谢!

参见 Ruby China 的 Topic model 的 last_active_mark 字段:https://github.com/ruby-china/ruby-china/blob/be74a05c48150cb2dd8d87df15154e0c1b384706/app/models/topic.rb#L32

原理

下面是 Mongoid 的源代码示例,ActveRecord 自行脑补

class User
  field :last_post_at, type: Integer

  index :last_post_at

  scope :last_actived, -> { order("last_post_at desc") }

  def touch_last_active
    self.update_attribute(:last_post_at, Time.now.to_i)
  end

end

class Post
  belongs_to :user

  after_create do
    self.user.touch_last_active if self.user
  end
end

class UsersController
  def activities
    @users = User.last_actived.limit(50)
  end
end

@huacnlee 确实,这样的方式确实很优雅。

原来是觉得没必要在用户表里面增加字段,现在仔细想想,在读取纪录次数远远大于更新纪录的次数的情况下,还是增加字段的方式执行效率高。

非常感谢!

需要 登录 后方可回复, 如果你还没有账号请 注册新账号