4

for a forum-like application I need the ability to show each user the unread (new) messages. Is there any Rails plugin/gem for that purpose?

Or: Are there any hints to do this job in a efficent way? I'm thinking about an additional database-table storing the unread-status (or read-status?) of every message for every user. But this seems to be brute-force method, perhaps there is a smarter solution...

Best wishes, Georg

Georg Ledermann
  • 2,712
  • 4
  • 31
  • 35
  • A little more information about your message structure would be useful. Are messages like Twitter? In that any one can read any message in any order? Are they like a forum post? Where messages are read sequentially? Are they like email? Where only one person will read each message? – EmFi Feb 18 '10 at 18:22
  • The messages are like forum posts. Many users are creating topics and replies to topics (both called "posts"). I want to show a hint like "There are 5 topics with new messages" for every user. I think about a table like this: UnreadMessages: - topic_id:integer - user_id:integer But if there arey lots of users or lots of topics, this table will be quite large. If there are 1000 users, for every new post there must be inserted 1000 records. AFAIR there is Rails plugin for such a thing, but I can't find it anymore and I don't know what database structure is being used. – Georg Ledermann Feb 19 '10 at 06:20
  • Interesting idea found here: http://stackoverflow.com/questions/1997399/how-do-forums-show-you-unread-topics "maintain a table containing all the threads and the latest post in that thread which each user has seen." – Georg Ledermann Feb 19 '10 at 07:33

2 Answers2

16

In the meantime I have created a Rails plugin based on my idea above, but with a more improved algorithm. Check it out here:
http://github.com/ledermann/unread

Georg Ledermann
  • 2,712
  • 4
  • 31
  • 35
  • Saved me a lot of work. Only thing that would be nice is being able to show posted as "edited" for users since they last read it. I'll fork and play with it. Again thanks a lot =) – Kansha Feb 05 '13 at 10:46
7

To whom it may concern, here is my solution. I have added a new table for storing the read status. A row in this table gives the number of posts a user has read so far in a given topic. If a topic has more posts then the user has read, it's called an "unread" topic.

Usage:

# Get number of unread posts of the logged-in user:
Discussion.unread_by(current_user).count
# => 42

# Mark a topic as read
some_topic = Discussion.find(x)
some_topic.read_by!(current_user)

Simple model "ReadStatus":

class ReadStatus < ActiveRecord::Base
  belongs_to :user
  belongs_to :discussion

  validates_presence_of :user_id, :discussion_id, :post_count
end

Extract from model "Discussion" for storing topics and posts:

class Discussion < ActiveRecord::Base
  belongs_to :user
  belongs_to :topic, :class_name => 'Discussion', :foreign_key => 'discussion_id'

  named_scope :unread_by, lambda { |user| 
      { :joins => "LEFT JOIN read_statuses ON (read_statuses.user_id = #{user} AND 
                                               read_statuses.discussion_id = discussions.id)",
        :conditions => "discussions.discussion_id IS NULL
                        AND (read_statuses.user_id IS NULL) OR (read_statuses.post_count < discussions.post_count)",
        :order => 'discussions.updated_at DESC' 
      }
  }


  def read_by!(user)
    if read_status = ReadStatus.first(:conditions => { :user_id => user.id, :discussion_id => self.id })
      read_status.update_attributes! :post_count => self.post_count
    else
      ReadStatus.create! :user_id => user.id, :discussion_id => self.id, :post_count => self.post_count
    end
  end
end
Georg Ledermann
  • 2,712
  • 4
  • 31
  • 35