Question

I have a Conversation model that has_many messages. In my query, I have

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

This solved my N+1 queries for the most part. Here is my problem:

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

There is no n+1 issue for conversation.message.body

The issue is with - if conversation.has_unread_messages?(current_user) because for every conversation it is running that query to check if the messages in that conversation have not been read.

Was it helpful?

Solution

As you have included the :messages on your query, you have all messages loaded, so you don't really need another query to check if it is unread and if all the conversation messages are unread. You can create methods that check these states:

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

All of your messages inside the @conversation.messages are preloaded.

Updated

Here is updated solution:

def has_unread_messages?(user) 
  messages.any? { |message| message.read_at.nil? && message.receiver_id == user.id } 
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top