Public Activity - show only activity about self created objects - ruby-on-rails

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.

Related

whether the paper trail has a way to track the user activity based on a specific role

I'm trying to use paper trail to track user activity in my application. i have set up the gem, followed the tutorial and made it work fine in my application..
but, when I test it as an ordinary user (as a guest user), paper trail also tracks this guest activity which the same model and controller...
Is there any way how to track the user activity based on role ?
i mean, i just want to track the activity of a specific role..
Need help..
paper trail
i just want to track the activity of a specific [user] role
You can turn PaperTrail off in your controller. From the documentation:
Turning PaperTrail Off
Per Request
Add a paper_trail_enabled_for_controller method to your controller.
class ApplicationController < ActionController::Base
def paper_trail_enabled_for_controller
!(cool_user? || trustworthy?) # :) this part is up to you
end
end
If that doesn't work, there are many other ways to turn PaperTrail on/off described the documentation.

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.

Rails User tracking activity

I want to track user activity on site. I tried ActiveSupport::Notifications but hasn't user_id or something to define a user. As I see, there are 2 ways to do this: through ActiveRecord queries, and through Page Requests. In the first case I should subscribe to all possible user actions with model (after_create, after_destroy etc.), and I have about 20 associated models, that is a lot of duplicate code. The second - I don't know how to do this, but it's seems simply to me.
I'm not using Device or any gem.
Perhaps in the first way, I could include module and make all logic in it, but It's not working.
The problem was solved by adding before_filter :track_activity in ApplicationController, ti calls every time when user enter any page.

How can I pull in data from other controllers/tables into one list?

I have a rails project where users sign up and login. Users will create "Music" so I have a "Music" controller, the user will fill in a title, and upload their MP3. Every user can do this -- this is dandy.
When a user logs in I want them to see everyone's uploaded music in a nice list view at http://example.org/explore. I will have some "latest additions since your last login" somewhere on the sidebar of this "explore" page in the future among some other features.
My question is, should I create a controller called "Explore" with an index action for this listing with something like the following?
class ExploresController < ApplicationController
def index
#music = Music.all
end
def show
end
end
I thought this might be the right way to do this but it seems odd to have the "Explore" controller be using all of the actions you'd typically see in the "Music" controller. The Music controller is going to be CRUD for the current_user.
You can easily have the music#index method available to everyone and put user authentication on the CRUD methods. That way everyone can see all the uploaded music on the /music page, but only the owner of each one can alter them.
If users need an easy way to see a list of use their own mp3s then you can just use a nested resource, so it would be available at /users/:id/music.
If you need some more info on how to implement that stuff then leave a comment. The specifics would depend on what (if any) authentication systems you were using.
It doesn't look a Rails way.
Use same Music controller( if it's just a CRUD inherited_resources is your choice ) with has_scope gem and manage user access with cancan.
This way you have a 5lines MusicController and no any additional controlers
It's perfectly fine to add an 'explore' action to the Music controller.
As to whether or not a new controller is warranted, how much in common does the Explore page you have in mind have common with functions from the Music controller? Can they share partials and helpers? Will they utilize the same callbacks?
If your only plan is to list all from another model in the new controller as shown, then I would say the answer is straightforward: keep in the in the Music controller.

Implementing Notifications in 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.

Resources