Rails:生成N + 1个查询

时间:2013-08-21 16:56:26

标签: ruby-on-rails ruby-on-rails-3 ruby-on-rails-3.2 eager-loading

我有一个has_many消息的对话模型。在我的查询中,我有

@active_conversations = Conversation.includes(:messages)..........

这大部分解决了我的N + 1查询。这是我的问题:

index.html.erb

<% @active_conversations.each do |conversation| %>

<div class="<%= 'unread' if conversation.has_unread_messages?(current_user) %>">

<span><%= conversation.messages.first.body.truncate(50) %></span>

</div> 

<%end%>

Conversation.rb

  def has_unread_messages?(user)
    !self.messages.unread.where(:receiver_id => user.id).empty?
  end

Message.rb

  def self.unread
    where("read_at IS NULL")
  end

conversation.message.body

没有n + 1问题

问题出在 - if conversation.has_unread_messages?(current_user),因为对于每个对话,它都在运行该查询,以检查该对话中的消息是否尚未被读取。

1 个答案:

答案 0 :(得分:4)

由于您在查询中包含:messages,因此您已加载所有邮件,因此您实际上不需要另一个查询来检查它是否未读以及是否所有会话邮件都未读。您可以创建检查这些状态的方法:

def has_unread_messages?(user)
  unread = self.messages.collect {|m| m.read_at.nil? && m.receiver_id == user.id}
  !unread.empty?
end

预先加载@conversation.messages内的所有邮件。

<强>更新

这是更新的解决方案:

def has_unread_messages?(user) 
  messages.any? { |message| message.read_at.nil? && message.receiver_id == user.id } 
end