Implementing Notifications in Rails - ruby-on-rails

In my application, I want to notify a user, when he/she is mentioned in a comment or a post.
The user handle is #user_name, similar to Facebook.
The database table for mentions looks like:
Mention
mentioned_by: user_id (foreign key)
user_mentioned: user_id (foreign key)
comment_id: (foreign key)
post_id: (foreign key)
I can't figure out a way to implement it though. How do Facebook / Twitter do it?
What I decided to go with, was use ActiveRecord callbacks/ Observer design pattern and whenever a new comment/post is saved to database, I can go through the contents of the post/comment, and look out for any mentions and then execute the notifications as required.
I get the feeling that there are some missing pieces and I am not getting it right.
Is this the best way of doing it?

Facebook and Twitter are not mid-size Rails applications. They are companies. The tech that runs them is distributed and mostly custom, especially in the case of Facebook.
The part that you seem to be grasping for is how they determine who to notify in a performant and scalable way. This is where shit gets real. You can find a lot of information about the architecture behind each on of them, and there is certainly a lot of great stuff to help you think about these things, but ultimately none of it is going to be something you implement into whatever application you're building.
http://www.quora.com/What-is-Facebooks-architecture
Facebook Architecture
http://www.infoq.com/news/2009/06/Twitter-Architecture
http://engineering.twitter.com/2010/10/twitters-new-search-architecture.html
Plenty more juicy details over at Quora.
Unfortunately, none of this gets you closer to your goal. I think the most realistic thing for you to do to start out with woud be to simply tie in a service like Pusher to send messages to clients without worrying about it, use an ActiveRecord Observer to add notifications to a background queue where the workers actually send those notifications to Pusher. This is a day or less of work and it should scale well to at least 10k notifications a day. Once you start having performance problems, ditch the Observer and Pusher for something like Goliath that can handle both of the jobs locally.
Bottom line, learn what you can about large and experienced systems that have been put through the paces, but mainly just to see what problems they ran into and how they solved them. These methods aren't the same among the big guys even, and they are going to vary for each implementation.
Hopefully that helps point you in a good direction. :)

You can use ActiveRecord callbacks while record is saved (like before_save, after_save or before_create, after_create) to go through comment content, find and create all mentions models and save them to db.

I actually am interested in a concrete answer to this myself. I don't know how Facebook and Twitter do it, but I do know from general searches that the gem acts-as-taggable-on could get the job done. Check out https://github.com/mbleigh/acts-as-taggable-on.
Also, this question on stackoverflow might also provide you with some info: Implementing twitter-like hashtag on rails
Good luck. I encourage you to try to get more attention to this question and get a more solid answer than what I've said. :]

Tumblr uses a Redis queuing system (like Resque) I believe to handle the volume.
Do a callback (as you mentioned) and hand it off to Resque. (There was a Railscasts about Resuqe recently)

There is no single recommended approach for this. At an uber level, you may want to look at 'Comet programming', Polling and WebSockets [HTML5] and then choose the right combination. There are a couple of great implementations to manage push notifications in rails. Orbited, Juggernaut, PusherApp, Faye etc. You'll have to dig deep to figure out which of 'em use web-sockets & and fall-back to flash option to handle full support.
Faye gives a Node.js configuration also, but I am not sure about others.
Tentatively the steps would look something like:
Save the content - queue it to parser
Parse the content to find out involved users - Use Nokogiri or equivalent.
Comet/Poll it to involved users in current_session as a separate process if you're looking at Twitter like approach.
//Do other things with Post record
Push notifications to involved users and destroy() when they come online later.
Hope that gives some direction.

I know this question is outdated but I released a MentionSystem gem recently to rubygems.org that allows to create mentions between mentionee objects and mentioners, it also allows you to detect mentions in facebook / twitter styler like #username1 and #hashtag in order to create the mentions.
The gem is hosted at github: https://github.com/pmviva/mention_system
Lets say you have a Post that can mention users in the form of #username.
you have the class
class Post < ActiveRecord::Base
act_as_mentioner
end
and
class User < ActiveRecord::Base
act_as_mentionee
end
Then you define a custom mention processor:
class PostMentionProcessor < MentionSystem::MentionProcessor
def extract_mentioner_content(post)
return post.content
end
def find_mentionees_by_handles(*handles)
User.where(username: handles)
end
end
Then in your Posts controller create action you have:
def create
#post = Post.new(params[:post])
if #post.save
m = PostMentionProcessor.new
m.add_after_callback Proc.new { |post, user| UserMailer.notify_mention(post, user) }
m.process_mentions(post)
end
respond_with #post
end
If your post has #user1, #user2 and #user3 in its content the mention processor will parse user1, user2, user3, will find users with username [user1, user2, user3] and then create the mentions in the database, after each of the mentions it will run the after callback that in the example will send an email notifying the mention between post and user.

Related

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?
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.
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
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:
Polling
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!
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.

Public Activity - show only activity about self created objects

I followed Ryan Bates Tutorial on Public Acticvity. I'm trying to show ONLY notifications about objects the current_user owns.
In my Situation => Comments.
my Activities Controller
class ActivitiesController < ApplicationController
def index
#activities = PublicActivity::Activity.order('created_at desc').where(owner_id: current_user.following_users, owner_type: "User")
end
end
I'm using current_user.following_users to get all followed Users. To get activity if they Upload a Picture.
AT THIS POINT: Activities are shown from all followed User's, and THATS the problem.. All activities.
I want to show only activities that concern the current_user, only activities about his own objects.
For example.
current_user Uploads a Picture, UserX comments on this Picture. I want the Notification.
UserX comments on a Picture from UserY. I don't want this notification.
For now if current_user follows UserX, i'm getting all the notifications from UserX's Activities, and not only the notifications that concerns the current_user.
But i'm completely clueless on how to achieve this. Has anyone some helping hand unoccupied ?
I found a pretty similar problem, but i don't understand the Answer -> Using public_activity with acts_as_follower and devise, how can I show only the user's activities and those of the people he follows?
Another one: Rails getting activity feed that only involves current_user
I think the feature you asked is a bit beyond the scope of general activities, but rather like notifications.
The "recipient" solution should be able to solve this exact problem. But you may still want the owner to show this activity, as well as the current_user. If so you need to create two activities and there needs workaround not to show them all in public. So, this may work, but duplicate record and extra code.
A better logic may be to process activities after created, judge the logic, and send notification, either on request or backend(better).
Notice: Sharmeless ad below :)
I have similar concern before and found it hard to reuse Public Activity's activity records again for other purpose. So I made a gem simple_activity which is even simpler on displaying activities but open the door to reuse them again. This gem is still at very early stage so be cautious. Check it if it helps.

Create a simple private message system in rails with inbox, send, and reply's?

There are some gems out there to instantly have a simple messaging system for users which I have looked at but they don't really fit the bill in terms of having a way to easy customize them.
Therefore I would like to ask some suggestions of gems that you consider be good for an instant messaging on a site, or discuss how one could implement this functionality.
I have built a simple system before that consisted of a messages table like this:
inbox
outbox
friend request
replies
id|message_id|sender_id|receiver_id|is_reply|is_friendreq|message
I'm thinking of storing everything in this one table and get all messages of a certain user where the user_id == receiver_id. This is very basic. I'm learning Rails and try to learn how to implement this on best Rails practice, so any tips/suggestions/ideas are more than welcome.

Rails 3 best way to create a comment system for posts

my first entry here.
I'm trying to add a comment system to our Posts model. However, I am not sure of the best way to go about it for a number of reasons. I'd like the comment system to be similar to that on Forrst.com but i'd rather have visitors who comment not need an account as the site is our company site not a large community.
Outline of features are:
Visitor can comment on post, entering name, email and comment.
Our team members can comment, i'd like these to be styled differently so would like the system to know it was from one of our team, they will be logged into the system when leaving a comment.
Visitors and team members can reply to a comment. The system needs to know which comment it was in reply to.
Lastly i'd like the system to know if the comment was written by the post author.
I have looked and been trying out acts_as_commentable_with_threading which seems perfect except everyone needs a user account to leave a comment, something I am trying to avoid unless anyone has other thoughts on that?
I have also implemented this myself by creating a comments model and using awesome_nested_set for the threading. Within the comments model I have a user_id which is only populated if the user is logged in (meaning they must be a team member), this seems a little messy though.
Does anyone have any thoughts on this?
Oh, and I would love each person to be notified of a reply to their comment (if pos).
Thanks in advance.
There are lot of tools available to post comments and working with ruby on rails.
http://ruby-toolbox.com/categories/rails_comments.html
also you can customize according your own requirement instead of writing a messy code.
If you do not want to integrate a third-party service like Disqus, you have Juvia The Comments and Commontator. Also you can count with opinio as alternative. but only with Rails 3 and at the moment and as notice the development seems stalled.

Rails application structure, advice?

I am about to start working on my second ever Rails application and could do with some advice. It will probably help in my head typing this question anyway!
The application's purpose is to track and monitor marketing campaigns. That makes it sound way more professional that what it actually is though.
An example usage:
Add list of possible client leads to application
Create a new "campaign" in the application
Choose who on the list of possible client leads should receive the
campaign
If and when a response is received it should then be possible to go into
that client lead's profile and mark
as "Positive Response" or "Negative
Response" etc..
Once the campaign is completed it should be marked as complete, I should be able to view in a campaigns profile who was a recipient of it and likewise if I view a client lead's profile I should be able to see which campaigns were sent to them and when.
That's the general idea of the application. I have made the framework and pushed it to GitHub:
http://github.com/dannyweb/Marketing-Manager
I am trying to get an idea of what models I would need, what sort of associations they should have etc.
I am unsure whether to use something such as acts_as_taggable and give each client lead a tag which relates to a campaign name?
If anyone can offer their thoughts or ideas on how this should be structured it would be greatly appreciated.
As it's my second Rails application - I am still very much a beginner, so please be kind! The application will remain open source on GitHub if anyone is reading this and would like to use the application.
Thanks,
Danny
I think you shouldn't turn to plugins (like acts_as_taggable) just yet. I'm going to give you some pointers but not much, because figuring out what works or doesn't is exactly what will help you learn more about rails.
So, you will have a 'Client' model and a 'Campaign' model. They have an N->N relationship (A campaign can involve multiple clients, and a client can be a part of multiple campaigns).
Therefore, you'll also need another table, which will have the 'client_id' and the 'campaign_id'. You also want to store on this table wether the client replied to it, so it'll need a 'replied' boolean flag on it as well. If you call this table 'campaign_messages', then client will need to link to campaigns using 'has_many :campaigns, :through => :campaign_messages'.
With these in place, you'll be able to list all clients on a campaign or all campaigns of a client easily. You'll also probably not need REST resource for the campaign_messages, only clients and campaigns.
That's all the detail I'm going to provide you. I think it'd be better if you just followed your approach now and asked how it could be improved instead.
Cheers and good luck

Resources