Rails: Keeping count of users unread notifications

后端 未结 2 1537
伪装坚强ぢ
伪装坚强ぢ 2021-02-02 01:22

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

相关标签:
2条回答
  • 2021-02-02 01:31

    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.

    0 讨论(0)
  • 2021-02-02 01:33

    There are a couple possible approaches to this: normalized and denormalized. I'll start with normalized:

    Approach 1: 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:

    • Activity belongs_to :user and has_many :notifications (one user performs an activity and multiple users get notified of the activity)
    • Notification belongs_to :activity and belongs_to :user and has a "read" attribute / flag
    • User has_many :notifications

    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)
    

    Approach 2: Denormalized

    In this approach, whenever an activity is created, it should manually increment a counter for each notified user. You can accomplish this with either:

    • An "unseen_count" attribute on user
    • A key-value pair in a non-relational database (e.g. redis)

    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.

    0 讨论(0)
提交回复
热议问题