I currently have an activity model that handles a user activity notification system. An activity observer creates a new activity when some action happens (such as a new article
Please have a look at this gem:
https://github.com/ledermann/unread
It's written by me and handles read/unread status of any ActiveRecord objects in a more performant way.
There are a couple possible approaches to this: normalized and denormalized. I'll start with normalized:
It sounds like you have three models in play here: activities, notifications ("user_activities"), and users. Correct me if I'm wrong in my assumptions here:
In an after_create callback on activity, the model should determine what users need notifications of that activity, and then notify them by creating notification objects for each of them.
On notifications, you can create a class method called unread which specifies a condition that the activity's read flag is false:
def self.unread
where(:read => false)
end
Then, to access a user's unread notifications count, simply call:
user.notifications.unread.count
When a user views his notifications, call:
user.notifications.unread.update_all(:read => true)
In this approach, whenever an activity is created, it should manually increment a counter for each notified user. You can accomplish this with either:
In Activity:
def users_to_notify
# Find a list of users to notify
end
def notify_users(users)
users.each &:notify
end
def after_create
notify_users(users_to_notify)
end
In User:
def notify
update_attributes(:unseen_count => unseen_count + 1)
end
def see_activities
update_attributes(:unseen_count => 0)
end
The downside to this approach is you've eliminated the Notification model, so a user only has a raw count of notifications, and can't view a detailed list of notifications and their associated activities. You could use a hybrid approach, but remember that it's risky to deal with two sources of truth for unseen notification count.
On a side note: it may make more sense to call notify_users in an observer instead of an after_create directly on the model:
class ActivityObserver < ActiveRecord::Observer
def after_create(activity)
activity.users_to_notify.each &:notify
end
end
If you use the observer, you can remove Activity#notify_users and Activity#after_create.