I'm using Intridea's Acts as Readable Rails plugin for a messaging system I'm currently building. I've defined my message class accordingly:

class Post < ActiveRecord::Base

And everything seems to be working according to plan, but when trying to execute to show unread messages in my message view, I'm running into problems.

Their example: (I've changed underscores to hyphens due to formatting issues)

bob = User.find_by_name("bob")

bob.readings                      # => []

Post.find_unread_by(bob)          # => [<Post 1>,<Post 2>,<Post 3>...]
Post.find_read_by(bob)            # => []

Post.find(1).read_by?(bob)        # => false
Post.find(1).read_by!(bob)        # => <Reading 1>
Post.find(1).read_by?(bob)        # => true
Post.find(1).users_who_read       # => [<User bob>]

Post.find_unread_by(bob)          # => [<Post 2>,<Post 3>...]
Post.find_read_by(bob)            # => [<Post 1>]

bob.readings                      # => [<Reading 1>]

So it seems as though if I wanted to list the number of unread messages sitting in a mailbox (for example Inbox (39) ), I should be able to do something like:

<%= Post.find_unread_by(current-user).count %>

But to no avail. I always seem to get stuck on the simple view issues after everything's set. Any ideas?

+8  A: 

The following will work

<%= Post.find_unread_by(current_user).size %>


<%= Post.find_unread_by(current_user).length %>

However if you check your development.log you should see that it gets the unread count by

  1. Retrieving all the posts
  2. Retrieving all the posts read by the user
  3. Removing all of 2. from 1. in ruby

This will be very bad performance wise with lots of posts.

A better way would be to retrieve the posts read by the current user and then use ActiveRecord::Calculations to get a count without retrieving all the posts in the database

Post.count(:conditions => [ "id NOT IN (?)", Post.find_read_by(current_user)])

This should go into your Post model to follow best practices of not having finders in the view or controller


def self.unread_post_count_for_user(user)
  count(:conditions => [ "id NOT IN (?)", Post.find_read_by(user)])

Then your view will just be

<%= Post.unread_post_count_for_user(current-user) %>
+1  A: 

Wow, I can't test this in my app until later on tonight, but you've succeeded in a) solving my problem and b) teaching me something new wrt convention. Thanks so much!

Bryan Woods