Doing Notification in Rails - ruby-on-rails

What i want to do is a little different from what people think when they hear rails notification cause i've been reading up a lot about it but it didn't seem to help.
What i want to do is on creation of a new entry in a particular table i want certain users (admins) to get a notification in their home page or whatever page they're in, as the notification apparatus would be in the navigation bar.
How would i go about doing this ? i'm an intermediate rails developer, and i'm using rails 3.2.13.
Thanks in advance!

There are a couple of things you'll want to do (I agree with the approach proposed by japed):
Create the notification model with the required fields, I would suggest make it polymorphic so you can have access to the object that triggered the notification later (for example: having notifiable_type and notifiable_id fields, if an article creation triggered the notification creation you can then do something like notification.notifiable and get the article that was created)
Place the callbacks that will generate the notification in place. for example: if you want to notify an admin every time a user creates an article, you can create the notification in the after_create method on the Article model.
Have a way to know if the admin has read the notification or not (so you can show him a counter of unread notifications for example). For this I would recommend using the unread gem: https://github.com/ledermann/unread
After the admin reads the notification (eg: after clicking on the unread counted) update the status of the notification (using the unread gem of course, not directly on the notification record), maybe with an ajax request.

Related

Sending newsletters with SendGrid and Rails - What is the best approach?

I have a rails app with sendgrid API setup and I can send transactional emails just fine. Now I want to be able to send newsletters but I'm a bit confused about the flow and how to keep track of which users want to unsubscribe from the newsletter.
The way I was considering doing this is when a use signsup to automatically send a request to the SendGrid API and add them to the contacts list, and if they want to unsubscribe from the newsletter or transactional emails from my app's settings page I can save this info in my app's DB but also send a request to sendgrid's unsubscribe list to change the value there too. Now I can create a newsletter in sendgrid and send it out from there without having to do anything within my app. One caveat to this approach would be if the users clicks the unsubscribe button via the newsletter and the value gets changed in sendgrid but the change won't be reflected in my app - To work around this would it be better to create a cron job that periodically checks sendgrid for any changes and then save them to my DB, or should the unsubscribe page be part of my app, and when they select unsubscribe I save it to my DB and then push the changes to sendgrid? If i do this approach, would I require users to sign in if they want to make these changes?
An alternative approach would be to forego creating any contact lists in sendgrid and just create the email in sendgrid and sent it out using a rake tasks to trigger the sending?
Apologies if this is a very basic question, but this is my first time trying to setup newsletters etc and can't seem to find anything online about the best strategy to take in order to do this - I hope this question makes sense.
Twilio SendGrid developer evangelist here.
This question is a little too opinion based for Stack Overflow, many of the options you describe will work but they rely on whether it's the right decision for your application. But, I will try to give some guidance.
First, however you approach this, I would recommend you set up subuser accounts within SendGrid so that your transactional and newsletter emails come from different subusers. This way unsubscribes from newsletters won't affect transactional emails.
I would use the SendGrid contacts list to send out newsletters. This gives you a lot of power over your contacts without you having to build things yourself. You can segment your lists, create unsubscribe groups (where a user can unsubscribe from a subset of your emails instead of all of them) and send emails from within SendGrid without bothering your Rails app. You can still set up to trigger a newsletter from your app using the API if you want to.
As for maintaining the user's subscription status, I would go with exporting the contact lists and keeping your database up to date that way. The important thing when sending to your contact list is that SendGrid has the source of truth for subscription status and your application can be a bit behind if it needs to be. The SendGrid docs for exporting contacts also say:
Twilio SendGrid recommends exporting your contacts regularly as a backup to avoid issues or lost data.
So this would fulfil that suggestion too.
As for the unsubscribe links, the easiest way is to use the SendGrid unsubscribe form, have SendGrid handle all the unsubscribes, and your exports can keep your database up to date. That also allows you to handle the addition of unsubscribe groups without any more code on your side.
With more work you could create your own unsubscribe form so that your database stays more up to date with the subscription status. Your choice over whether a user should be logged in or not depends on how much friction you want to give the user before they unsubscribe and how much issue you think you might get from users forwarding your emails and having their friends unsubscribe them. That is up to you to decide on though.
Hope this helps a bit!

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.

How do I implement bubble notifications in rails?

I already have a feed with the public_activity gem . However, I want to have a facebook-like on-site notification system where the user can see a number in red background, representing the new notifications concerning him.
I have never implemented such a thing and I am not sure how to go about it.
Most answers about Rails notifications will recommend using Mailboxer, public_activity, and any other messaging gem but nothing about the dynamic real-time facebook like notification that easily alarms you of the new notifications with the number and links.
Thanks for your help !!!.
You can use polling with a JS library like jQuery. There is another good example that can be followed.
The main focus would be making an ajax request after a specific time and check for the results and repeat the process.

General Guidance on Rails Mailers

I am making an event registration tool in Rails and I am having trouble working out the mailing section. I am using Mailgun API and I've got a generic "Thank you for Registering" email working when the user signs up as well as a contact form submission that comes to my email. Part of the requirements for the application is the ability to send promotional emails (separate from Thank you for Registering emails). These promotional emails are more like (One week reminder) type emails.
So these emails need to be able to be created by the admin setting up the event as this is a general purpose tool. So to save the emails the admin creates, I have a mailings object. So the relationship is a bit like this:
Event has many mailers, registrations, etc. (and those belong to the event). They are nested resources because they are specific to an event. Now I need to bridge the gap of how to go from the mailers created by the admin to sending them to Mailgun. The problem is we will have to have the ability to add recipients because they may want to send to people besides the registrants for the event. So I need to go from the mailing#show (which shows a preview of the mailing and will need to be able to add/remove recipients), loop through all of the recipients, and send the message that is in the mailing.message field.
I am so close to finishing this tool except for this mailing which I cannot wrap my head around. I see a lot of examples that create a mailer but I am not sure if that would work for me since the message are unique and it needs to get the message and subject from the mailer object. Any advice or guidance? I am really struggling to get this part done.
I assume you have a User model with an email column
I would setup an extra model i.e.
class PromoMail < ActiveRecord::Base
has_many :users # recpients
validates :body, presence: true
end
Then add a controller, where admins can create these and insert the Mail content in the body field and add recipients.
Then create a new method in your existing mailer to send the mail with the yielded body to one user.
Then add a action to the forementioned controller to send the PromoMail by looping over the associated users and call the ne mailer metod with each.
Couple of steps here, without going into much detail.
1) Make a rake task which looks for any emails which needs to be sent out, and sends them out. You might need to expand your schema to record whether a mail (or mailing or whatever) has been sent already. The rake task itself shouldn't have much code, it should just call a class method in eg User or Mailing or something.
You'll need to think about how the system can decide which emails need to get sent out. I find that flowcharts can be helpful here: it's going to involve iterating over all users, or all mailings, or something, and applying various logical tests to them. You may find that your current schema isn't up to the job, in which case expand it.
2) Schedule this rake task to be run at regular intervals, eg once a day or once a week. Various scheduled task runners are available, eg cron, or if you're on Heroku you'll need to use their Scheduler tool, for example.

Rails-way to implement site-wide notifications

I'm not new to MVC but I'm new to Rails, and I'm struggling trying to make everything "the Rails way". I want to implement site-wide notifications, so I've created a Notification model and created the many-to-many relationship between User and Notification.
The problem I face is when creating notifications, I have several entities which generate notifications in my code. You might get a notification when someone replies to a forum post you follow, you get a new private message, someone follows you, favs one of your entries, etc. I don't really know how to create new notifications.
Creating them in the controller feels bad, it can result in fat controllers very easily. I know about Service Objects and I love them, but I'm unsure if I should use them in this situation. I could have, for example, a notifications service which takes care of all notifications.
Another thing I thought is making all models which can generate notifications a "to_notification" method which returns the message the notification has, for example, the PrivateMessage model would have a method to_notification which returns You've got a new private message from #{username}.
The third solution I considered is adding a notify_user(user, message) method in the Notification model. But I guess the Controller still has to manage quite a lot of logic, like the notification message itself.
What is the most Rail-ish way to solve this?
Edit: I'm aware of Mailboxer but I'd rather do it myself.
Update
Okay so I ended up using a service object. Here's the Notification model
class Notification < ActiveRecord::Base
validates :message, presence: true
belongs_to :user
end
Pretty simple, then I created an action called NotifyUser in app/actions/notify_user.rb which takes cares of sending notifications
class NotifyUser
def initialize(user, message)
#user = user
#message = message
end
def notify
Notification.create(user: #user, message: #message)
end
end
Finally to send a notification I just call the action's notify method by doing NotifyUser.new(user, message).notify.
The logic for the notification message is handled directly in the controller or action. For example:
def follow(user)
success = current_user.follow user
message = "You've got a new follower, #{view_context.link_to(current_user.username, current_user)}!"
NotifyUser.new(user, message).notify if success
end
I still can't think of a more elegant way to create the messages. I guess this works good enough for me.
I prefer service objects for a non-trivial app. Here are my personal opinions.
Suppose you have a typical use case where a user sends a message to another user, e.g. Alice sends a notification "Hello" to Bob.
Here's an example of creating them in the controller that is "the Rails way".
Alice visits a page such as "www.example.com/notifications/", writes her message, taps the "Send" button.
Rails uses NotificationsController to create a new Notification model instance, i.e. record in the database.
When Bob signs in, the app queries the notifications to see if any are for Bob.
Here's an example of creating them using a service object:
You have a file such as "./app/services/notifier.rb" that exposes a plain old Ruby object such as "Notifier".
The Notifier object has a "send" method (or whatever methods you want).
The method takes care of creating a new Notification.
Here is an example of a hybrid:
E.g. a typical NotificationsController has some extra code: a non-user-visible class-level method, such as "def self.send".
The controller does double-duty as a typical REST resource CRUD manager, and also as a service object with an internal-facing API method.
My personal experience with this kind of hybrid is it works and it's easy for quick apps because everything's in one place, yet in a real app the hybrid tends to grows into a big ball of code that is hard to test with clean separation, mocks, and stubs.
To show the notifications to the user, and let a user interact with a notification (e.g. edit, delete), I do recommend a typical Rails controller, because notifications are essentially resources.
Another thing I thought is making all models which can generate notifications a "to_notification" method
Don't do this if you're building a real app. I've had to clean up many apps like this. Also it gets hairy when internationalization and localization are involved.
The only solution I've seen succeed this way is DCI, which can add a to_notifciation method at the point in time you need it. It's a great way to do it, except that DCI tends to run slowly in Ruby.
I considered adding a notify_user(user, message) method in the Notification model.
This is essentially making a class that is a hybrid: it does double-duty as your resource and as your service object.
It's fine, but it's harder to reason about because it's mixing model-related concepts (e.g. business logic, record persistence, etc.) with controller-related concepts (e.g. creating new resources).
As above, it's fine for a quick app, yet tends to grow into a big ball of code that's hard to test cleanly.

Resources