Rails ApplicationCable and Channels best practice? - ruby-on-rails

I am currently using Rails to prepare backed for reacting and react-native applications. The token is used for authentication.
I've got two features in my application, which require WebSockets:
Chat system(one chat open at a time)
Notification system
I see two ways to implement WebSockets:
Two separate channels
First channel: NotificationChannel to which I subscribe when client opens application and then I broadcast sth if it is required
Second channel: ChatChannel to which I subscribe when I open a chat, the code would look as follows:
class ChatChannel < ApplicationCable::Channel
def subscribed
authorize_chat_room_id(params[:chat_room_id]) #
stream_from "chat_channel_#{params[:chat_room_id]}"
end
# here methods for receiving data from client
# maybe some other methods for tracking if sb is typing and so on
# private authorize_chat_room_id method
end
In this scenario user is subscribed maximally to 2 channels and authorization is performed only once when subscribing to chat.
In this approach, I authorize only once the user, when he subscribes to channel, however, I don't know how having 2 channels opened instead of 1, affects performance on the server.
One channel
The single channel would be called: PersonalChannel, and would take care of all information flow, the code would look sth like this:
def subscribed
stream_from "personal_channel_#{current_user.id}"
end
def send_message(data)
if authorize_chat_room_id(data['chat_room_id'])
#create message
end
end
def start_typing(data)
if authorize_chat_room_id(data['chat_room_id'])
# some broadcast
end
end
And when I would broadcast, then I would send in the payload for example type(ex. 'MESSAGE_SEND'), and based on that, react client would print the message if chat would be open.
The advantage of this approach is that when sending the message I can broadcast only to one user and I won't get back message from the channel. But in this case, I have to authorize each time performed an action.
My question is which solution would be better in case of performance and what is generally accepted approach(to make Channels very general or to make each Channel take care of single task)?

On this issue, I would suggest that you consider prioritizing code maintenance concerns over performance.
The concept of channels allows us to decouple publishers from consumers. This simplifies a lot of code and helps with separation of concerns.
For example, a user posting in a chat room wouldn't need to know (nor manage) how many people are subscribed to that chat room, nor who they might be. These concerns are now handled by the pub/sub system rather than the user.
This separation of concerns makes adding or removing chat members much easier (you don't need to updated every user, you only need to update the pub/sub system).
This separation also prevents multiple copies of the data from being stored (the pub/sub system holds the only valid copy).
In the long run, by consolidating all the data into a single PersonalChannel, you'll be reintroducing the coupling between publishers and consumers - this will increase complexity and make maintenance mode difficult over time.
In the chatroom example, each user will need to grab a copy of all the room's members and send each message to all users. This increases the number of copies (of the member's list) as well as introduces synchronization concerns.
The advantage of this approach is that when sending the message I can broadcast only to one user and I won't get back message from the channel. But in this case, I have to authorize each time performed an action.
This advantage is actually something you can easily achieve using the first approach by subscribing each user to a personal channel as well as the other channels, subscribing to three channels instead of two.

Related

sociometrical score of slack API

So I got a task to prepare a simple analysis on how useful, from sociometrical point of view, are Slack API methods (https://api.slack.com/methods).
Yesterday I didn't even know that such thing as sociometry exists, and i still dont know how to evaluate any API using its methodology. Does anyone here ever got a similar task, or have any idea how to approach such analysis? What literature will be useful? I don't mean this analysis to be particularly long, but as for now I don't even know where to start.
Frankly, I am not an expert on sociometry , but here is how I would approach it:
I would assume the goal is to create a sociogramm depicting the relationships between all users on a Slack team using the API methods. So the question is how useful the API methods are to achieve that goal.
Slack does not have a "friends list", like Facebook, so you have to come up with your own approach on how to identify relationships on Slack. Slack is a messaging system, so it makes sense to define it based on who is communicating with whom.
Lets define users to have a relationships if they are
direct messaging each other (including groups)
talking to each other in a channel (using the #user
mention)
or just being part of the same channel and talking in the channel
Now to assess the effectiveness of the API methods. The basic approach would be to retrieve the messages of a public channel with channels.history (or im.history for direct messages, groups.history for for private channel and mpim.history for direct messaging channels with multiple participants) for a given time period. In addition you can retrieve the members of a channel with channels.info (or their pendants for the other channel types). Then you would parse all retrieved messages and the member list of a channel to identify the relationship and calculate the sociagram.
However, Slack will only allow users to access channels, that they are members of. That includes access through the API and that includes users with the role admin and owner.
So its not possible to see all direct messages, groups chats and private channel of a Slack team through the API and we would therefore need to limit the approach to public channels and some private channel. Depending on where most of the conversation is happening on a specific Slack team and which private channels our slack user is a member of this could significantly limit the ability to calculate a complete sociogram.
In summary you can use the API methods to calculate a sociogram for your Slack team based on which users users are communicating with each other. But that analysis will not be 100% complete, since its not possible to access all private communication on a Slack team though the API. The calculated sociogram might still be useful though, if the Slack user doing the calculation has access to all relevant private channels.

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.

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.

Pubnub many private chats in ios

I am developing an ios app like Tinder. Users can chat only in private 1:1.
Should I have to open one channel for every single "match"? Is this the correct design pattern for this case study? What about performance if i have one channel per "match".
*Match" is when a user matches to another and can start a private chat.
If one person can have multiple matches, you can ask PubNub client to open separate channel for each nothing person. So, when you have two matching persons, you take some unique identifiers from both of them and using known algorithm create unique name of the channel for which both clients will subscribe to communicate.
One channel for whole application - really bad idea, because of possible massive flow of data, which for most of subscribers will be useless, because consumer is one of other subscribers.
Yes, the best approach is that every "match" should have it's own channel on which both participants publish/subscribe to communicate. PubNub has no limit on channels (nor does it charge based on channels), so this shouldn't create a performance or cost issue.
To add access control to the "match" channel (if you want to ensure no one else can access that channel), use PubNub Access Manager, documented here: http://www.pubnub.com/docs/javascript/tutorial/access-manager.html (use dropdown to change programming language)
If you want to provide chat history, so that the two participants can see messages from previous chat sessions, enable PubNub Storage & Playback, and use the PubNub.History() API, documented here: http://www.pubnub.com/docs/javascript/overview/storage-playback.html
If you want to see when those two participants are connected to the Match channel, use PubNub Presence, documented in the same place.

Concurrent moderating on a CMS

I'm building a custom CMS which allow user to post message to it. Messages are short and like tweets.
The problem is that these message are moderated by real moderators. And there are multiple moderators working on the messages stream at the same time. And my concern is that what if these moderator are processing a same message. This is both inefficient and inconsistent. Since one message can be rejected by one moderator and then passed by another.
Therefore I want to build some kind of mechanism so that the CMS can distribute these messages to different moderator and avoiding duplication. The CMS is expecting to deal with large volume of message in a short time. Therefore this problem become more serious.
Any Idea is appreciated. Cheers.
I would do it like this:
Each logged-in moderator gets his own queue of messages to moderate
There is a central queue which will be used as a buffert
Posted messages go into the central queue
Each moderator queue fetches, say, 10 messages at a time.
When there's only 5 left in a moderator queue that queue will automatically fetch 10 new messages.
The downside is that you will need a central queue with a locking mechanism. If you want to avoid even that locking I propose one of two solutions:
Remove the central queue entirely and post messages on-the-fly into one of the moderator queues (maybe a randmoly chosen one), or,
Have a central queue and let each moderator have a randmoly chosen message from the top part of the queue (e.g., let them have one from the top-20). If there is "double moderation" due to absense of locking, just ignore the second moderation and accept the time-waste.
You could have the moderators pull the message off a queue before moderating. Sort-of like a check-out? So the moderator clicks something that assigns them a number of messages to process. They deal with those, then grab another batch off the queue.
Have your update action for Messages do this
def update
# perform regular update stuff ;)
rescue ActiveRecord::StaleObjectError
flash[:message] = "Someone else has updated this message"
redirect_to message_path(#message)
end
Check out http://railscasts.com/episodes/59-optimistic-locking or other pages on 'locking' (optimistic or otherwise) in Rails.

Resources