kpaul
kpaul

Reputation: 479

Approach to a Notifications system with Rails 4

I have a USER model in rails that I would like to implement a notifications system for.The notifications system is intended to work like Facebook's notifications. Using guides around the internet as a basis, I have theorized that notifications would require its own Model.

Therefore it would be:

Users :has_many Notifications 
Notifications :belongs_to Users

The Users model interacts with many models on the app such as articles, post, comments on the articles and posts. Users can "follow" those resources and receive notifications for them. My theory is that I create notifications for each "follower" whenever those resources are updated like so:

Example of Update for an article:

def update
   #after the code to update article
   @followers.each do |follower|
       Notification.create(#code to associate notification with user)
   end
end

Then, just display the notification using

current_user.notifications 

My primary question is that Is there a better approach to notifications than what I've outlined? Also on a related note, creating notifications like so would fill up the rows in the database with objects that are not needed over time(i.e notifications from a year ago are irrelevant). Is there any negative consequences for leaving those unused objects in the database and letting them add up?

Upvotes: 2

Views: 2346

Answers (4)

ChiefRockaChris
ChiefRockaChris

Reputation: 653

If you are open to using a gem, I would use the Public Activity gem for this. The architecture for Public Activity creates an activity record based on a recipient, an owner and a key, i.e owner: "User 1" key: commented on recipient: "User 2" post. The benefit to this is that there is only one record in the database for the activity and you can present it any way you like through different views for each type of activity.

Public Activity allows you to render different partials based on the activity key and access any of the data of the action referenced in the database. You can even create different views for a newsfeed(activities that involve the users followed by the current user) and a notification feed (activities that directly involve the current user). This allows your notification feed to remain flexible.

Further, if you combine it with the Unread gem and some javascript you can even mark read and unread notifications (for each particular user) just like Facebook. The only drawback is that the activities would appear only on refresh or visiting the page rather than constant polling like facebook does. There is an excellent tutorial on Public Activity here.

Upvotes: 2

br3nt
br3nt

Reputation: 9566

If all articles, posts and comments, are sources of notifications, it seems to suggest that you could use Single/Multi Table Inheritance or Polymorphism, rather than generate a notification record for each subscribed user for each post, comment, and article.

So, for the sake of argument, let the collective name of articles, posts and comments be Notifications. One notification for each article, post, and comment.

Now it just becomes a matter of working out how to keep track of the Notifications a user has seen. It could either be a simple column on the Notification table that holds a list of user ids {user_1}{user_5} that can be used to filter the records, or a many-many table that stores the user id and the notification id a user has seen. I'm sure there are many more possibilities, but I'm not familiar with the different approaches.

Using this info, it shouldn't be too hard to determine which Notifications have not yet been seen, and then display a message of such.

Upvotes: 1

Gustavo Rubio
Gustavo Rubio

Reputation: 10747

While that would work you would still have a problem: how to push those notifications to the user. What this means is that if I get notifications from the system yet I don't reload the page I won't notice until I do so which brings you to two different solutions, which have to do with the client side management of it really:

  1. Polling
  2. Something around WebSockets

Polling

In case you decide to go with the option number 1 you would need to add client-side JavaScript code that keeps polling one endpoint of your application to check for the current user notifications so you can update the UI.

Pros: You have a great control over the client side code and this can be implemented in almost all browsers as long as they support JavaScript. You can support legacy users.

Cons: Tedious to develop and can code can become messy. Not real time at all. Sometimes, using timers in several places within the same client code can lead to unexpected behaviors.

WebSockets

This is a newer technology so while it should work right out of the box in most modern browsers there are still some caveats here and there, which is the reason why few developers still avoid it. Web Sockets basically allow to have an open connection to the application (because as you may know HTTP is stateless) so that you can actually push or send notifications from the application and not the other way around (like when polling, where the client requests for the new info)

Pros: Newer technology but also more flexible in the way that you can control many aspects of the notifications in the backend (like having queues, a different, speedier, data store like nosql for it, etc.)

Cons: Some browsers don't properly support it yet.


I would say that if you are still developing your app and plan to release a little bit later and you don't mind some users having that option disabled when they have ancient browsers then take a look at ActionCable from Rails 5 which serves exactly this purpose. Here's a video from dhh doing a whole demo.

I would also separate notifications from your SQL table and instead of using ActiveRecord just use redis or mongo for that purpose while you keep ActiveRecord for everything else. The advantage is that redis and mongo are super fast and are well-known to outperform SQL in these kind of requirements. You can use the ActiveRecord user ID to map the notifications within the nosql database and subscriptions to those as well.

Good luck!

Upvotes: 1

Shishir
Shishir

Reputation: 780

I would use observers for notification as its an orthogonal concern to your model. See https://github.com/rails/rails-observers. for earlier versions of rails, it is part of the framework.

I would create a class Notifier which would observer lifecycle event (in the above case after_update on user) and would send out notifications. One observer can observe many models

Upvotes: 1

Related Questions