有效计算关联的关联

时间:2013-11-09 03:12:17

标签: ruby-on-rails activerecord eager-loading

在我的应用中,当UserComment中生成Post时,会生成Notifications,将该评论标记为未读。

class Notification < ActiveRecord::Base
  belongs_to :user
  belongs_to :post
  belongs_to :comment

class User < ActiveRecord::Base
  has_many :notifications

class Post < ActiveRecord::Base
  has_many :notifications

我正在创建一个索引页面,其中列出了用户的所有帖子以及仅针对该用户的每个帖子的通知计数

# posts controller
@posts = Post.where(
    :user_id => current_user.id
  )
  .includes(:notifications)

# posts view
@posts.each do |post|
  <%= post.notifications.count %>

这不起作用,因为它计算所有用户的通知。在不在每个帖子中运行单独查询的情况下,为单个用户计算通知的有效方法是什么?

3 个答案:

答案 0 :(得分:1)

Found a solution!

# posts controller
@posts = Post.where(… 
@notifications = Notification.where(
            :user_id => current_user.id,
            :post_id => @posts.map(&:id),
            :seen => false
        ).select(:post_id).count(group: :post_id)

# posts view
@posts.each do |post|
  <%= @notifications[post.id] %>

似乎足够有效。

答案 1 :(得分:0)

你可以这样做:

@posts=Post.joins(:notifications).where('notification.user_id' => current_user.id)

其中notification.user_id是current_user

通知的ID

答案 2 :(得分:0)

我建议创建一个小类来封装通知集合的逻辑:

class NotificationCollection
  def self.for_user(user)
    new(Notification.where(user_id: user.id))
  end

  def initialize(notifications)
    @notifications = notifications
  end

  include Enumerable
  def each(&block)
    @notifications.each(&block)
  end

  def on_post(post)
    select do |notification|
      notification.post_id == post.id
    end
  end
end

然后,在您的控制器上:

@user_notifications = NotificationCollection.for_user(current_user)
@posts              = Post.where(user_id: current_user.id)

最后,在你看来:

@posts.each do |post|
  <%= @user_notifications.on_post(post).count %>
end

这样,您只需要为每个用户执行一次通知查询 - 而不是像在数据库上执行COUNT()一样,但如果单个用户的通知低于数百,则应该足够。< / p>