Rails: учет количества непрочитанных уведомлений пользователей

В настоящее время у меня есть модель активности, которая обрабатывает систему уведомлений о деятельности пользователя. Наблюдатель активности создает новое действие, когда происходит какое-либо действие (например, создаваемая новая статья). Теперь я хочу сохранить запись о том, сколько из этих уведомлений о деятельности, которых не видел текущий пользователь (аналогично уведомлению на facebook). Каждый раз, когда пользователь нажимает на свою ссылку на уведомления, номер должен reset до 0, и каждое созданное уведомление должно увеличивать количество на 1. Где я буду хранить эти данные для каждого пользователя? Использует ли сеанс работу или что-то еще лучше?

Ответ 1

Существует несколько возможных подходов к этому: нормализованный и денормализованный. Я начну с нормализации:

Подход 1: Нормализованный

Похоже, у вас здесь три модели: действия, уведомления ( "user_activities" ) и пользователи. Исправьте меня, если я ошибаюсь в своих предположениях здесь:

  • Деятельность принадлежит_у: user и has_many: уведомления (один пользователь выполняет активность, и несколько пользователей получают уведомление об активности)
  • Уведомление принадлежит_у: activity и принадлежит_to: пользователю и имеет атрибут "читать" /флаг
  • Пользователь has_many: уведомления

В обратном вызове after_create на активность модель должна определить, какие пользователи должны получать уведомления об этом действии, а затем уведомлять их, создавая объекты уведомлений для каждого из них.

В уведомлениях вы можете создать метод класса, называемый непрочитанным, который указывает условие, что флаг чтения активности имеет значение false:

def self.unread
  where(:read => false)
end

Затем, чтобы получить доступ к счетчику непрочитанных уведомлений пользователя, просто вызовите:

user.notifications.unread.count

Когда пользователь просматривает свои уведомления, звоните:

user.notifications.unread.update_all(:read => true)

Подход 2: Денормализованный

В этом подходе всякий раз, когда создается действие, он должен вручную увеличивать счетчик для каждого уведомленного пользователя. Вы можете выполнить это с помощью:

  • Атрибут "unseen_count" для пользователя
  • Пара ключ-значение в нереляционной базе данных (например, redis)

В действии:

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

В User:

def notify
  update_attributes(:unseen_count => unseen_count + 1)
end

def see_activities
  update_attributes(:unseen_count => 0)
end

Недостатком этого подхода является то, что вы исключили модель уведомления, так что у пользователя есть только количество уведомлений и не может просмотреть подробный список уведомлений и связанных с ними действий. Вы можете использовать гибридный подход, но помните, что рискованно иметь дело с двумя источниками истины для подсчета невидимых уведомлений.

На стороне примечания: может быть более целесообразно вызвать notify_users в observer вместо after_create непосредственно в модели:

class ActivityObserver < ActiveRecord::Observer
  def after_create(activity)
    activity.users_to_notify.each &:notify
  end
end

Если вы используете наблюдателя, вы можете удалить Activity # notify_users и Activity # after_create.

Ответ 2

Пожалуйста, посмотрите на этот камень:
https://github.com/ledermann/unread

Он написан мной и обрабатывает прочитанный/непрочитанный статус любых объектов ActiveRecord более эффективным образом.