Ok, so you guys know the drill. I have users they log onto the site. I need a way to determine which users are currently logged onto the site. What is the "Rails" way to do this. I am willing to use whatever method is considered best practice. I have found this article: http://matt-beedle.com/2006/12/13/rails-how-to-find-out-who-is-online/ This seems pretty straight forward. Is this essentially the accepted standard for how to do this? The gist of it is reading the information out of the sessions column. I already use sessions and the active_record store so basically it just means: def who_is_online @whos_online = Array.new() onlines = CGI::Session::ActiveRecordStore::Session.find( :all, :conditions => [ ''updated_at > ?'', Time.now() - 10.minutes ] ) onlines.each do |online| id = Marshal.load( Base64.decode64( online.data ) ) @whos_online << User.find(id) end return @whos_online end My question is how often is the "updated_at" field updated? Only when I log in? Do I need to update the field myself before every controller action? This method requires me to get a list of id''s and then go through and do a query for the information of every single user. Basically, I am just curious if this is the smart way and be done with it or if I am missing something. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
updated_at is updated every time you save your model. because of the stateless nature of HTTP you cant know who is online. the last request was made. the simplest way to track if a user is logged in is to add a reoccurring ajax call to your layouts. that way as long as their on your site your app will be notified every x seconds. when this request comes in go into the session and if there is user info there get the user object and save it. now you can do something like User.find(:conditions => [''updated_at > ?'', 5.min.ago]) Note that this is very resource intensive and should be avoided if at all possible. It might even be worth while to create an active_users table that stores user_id and an updated_at to track who did what how long ago which may reduce the overhead though not by much. consider this a optimization to try if you need it and not before -K -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Jan 18, 2008, at 8:54 AM, Nathan Esquenazi wrote:> Ok, so you guys know the drill. I have users they log onto the site. I > need a way to determine which users are currently logged onto the > site. > What is the "Rails" way to do this. I am willing to use whatever > method > is considered best practice. > > I have found this article: > > http://matt-beedle.com/2006/12/13/rails-how-to-find-out-who-is-online/ > > This seems pretty straight forward. Is this essentially the accepted > standard for how to do this?That technique loops over the entire sessions table and unmarshalls each record. That''s expensive. These are alternative approaches. They assume it is enough for your purposes to define "being logged in" as having done a request within some time window: 1. The users table has a timestamp column seen_at that is updated each time a user makes an authenticated request. There you count the number of users whose seen_at belongs to the time window in a single query. This approach works with any session storage. 2. If you have a sessions table add to it a user_id column and maintain it with a callback in the Session model. There you count the distinct non NULL user_ids whose session updated_at belongs to the time window. That''s again a single query. -- fxn --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Thanks for your input so far. If anyone has more suggestions keep them coming but I am interested in your option 1 Xavier. Essentially, add a "seen_at" field to user and then update it every time they do something that requires being logged in. Then I could just query: User.find(:conditions => [''seen_at > ?'', 5.min.ago]) and to update seen_at, I could simply add a before_filter in my application controller that checks if there is a current user and if there is simply update their ''seen_at'' attribute. Does that cover the basics of the idea? I think I like it. Would any others agree this is a good approach or am I missing a major downside to this method? Xavier Noria wrote:> > 1. The users table has a timestamp column seen_at that is updated each > time a user makes an authenticated request. There you count the number > of users whose seen_at belongs to the time window in a single query. > This approach works with any session storage. >> -- fxn-- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Jan 18, 2008, at 10:32 AM, Nathan Esquenazi wrote:> Thanks for your input so far. If anyone has more suggestions keep them > coming but I am interested in your option 1 Xavier. > > Essentially, add a "seen_at" field to user and then update it every > time > they do something that requires being logged in. Then I could just > query: > > User.find(:conditions => [''seen_at > ?'', 5.min.ago])Sure you are aware of this, but just for the archives let me comment that would instantiate all the records as AR objects, that''s very expensive in general. If you were just interested in the number of people online it is much better to ask directly for the count: User.count(:conditions => [''seen_at > ?'', 5.minutes.ago]) With this solution you can also define a simple predicate class User < AR::Base def online? seen_at && seen_at > 5.minutes.ago end ... end Etc. It works quite well.> and to update seen_at, I could simply add a before_filter in my > application controller that checks if there is a current user and if > there is simply update their ''seen_at'' attribute. > > Does that cover the basics of the idea?That''s right. -- fxn --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Thank you Xavier. I love this place. I can post a question and have it answered well within a couple of hours. I understand about the count being cheaper but in my particular case I actually need to display a list of all users that are your friends and who are also online like a buddy list so I think the expense of creating the AR objects may be necessary. Thanks again though. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Jan 18, 2008, at 11:32 AM, Nathan Esquenazi wrote:> I understand about the count being cheaper but in my particular case I > actually need to display a list of all users that are your friends and > who are also online like a buddy list so I think the expense of > creating > the AR objects may be necessary.Good, then the fine point is to scope the query directly to the user''s friends. For example this way: class User < AR::Base has_many :friends, ... def online? seen_at && seen_at > 5.minutes.ago end def friends_online friends.select(&:online?) end ... end -- fxn PS: That implementation is clean but fetches the entire collection of friends. That could make sense depending on the application, otherwise just fetch the online ones scoping with friends.find(...). --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Xavier Noria wrote:> def online? > seen_at && seen_at > 5.minutes.ago > endseen_at < 5.minutes.ago ;) Also, 5 minutes is a bit harsh of a definition of being online. You might want to implement an away status too especially if youre going for the buddy list feel. def online? seen_at && seen_at > 20.minutes.ago end def active? seen_at && seen_at > 20.minutes.ago end def away # something in between end And don''t forget that when a user logs out (or their session gets cleared because they spent too much time away from the app) you might want to nullify seen_at as it would be redundant or at least kind of pointless to store both seen_at and updated_at. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
err: def online? seen_at && seen_at < 20.minutes.ago end def active? online? && seen_at < 5.minutes.ago end -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Jan 18, 2008, at 6:11 PM, Glenn Gentzke wrote:> def online? > seen_at && seen_at < 20.minutes.ago > end > > def active? > online? && seen_at < 5.minutes.ago > endOh, I thought because of the code that the first "sentence" was kind of a joke, but looks like it was not :-). If a user just did a request you certainly want to consider him to be online, right? $ script/console Loading development environment (Rails 2.0.2) >> seen_at = Time.now => Fri Jan 18 18:25:30 +0100 2008 >> seen_at > 5.minutes.ago => true 5.minutes.ago marks a point past in time. A user is online if it has been seen *recently*, so seen_at has to be greater than what you consider to be recent enough. Note that ">" is defined such that today > yesterday. -- fxn --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
william.harding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
2008-Jan-28 21:24 UTC
Re: "What users are online?" function
I recently wrote a follow up to Matt Beedle''s blog on my own blog: http://www.williambharding.com/blog/?p=99 A couple differences between his approach and mine: * I added fields to the session model itself to avoid the Marshalling/ Unmarshalling to find a specific attribute within the session * He doesn''t discuss exactly how (or if) he goes about updating which users have been seen when. I discuss how I did it with a before filter that does one SQL Update statement, which is about as efficient as possible * My query for users online is scoped such that it only returns the fields I need (using a :select), and it limits the number of users returned Generally speaking, I needed a solution that performs as well as possible, since it will be called extremely often (both to update when a user was seen and to find which users have been seen recently). I think that the solution I came up with ought to fit the bill pretty well, though I''d welcome any comments if others have tweaks to my approach. Bill On Jan 18, 9:31 am, Xavier Noria <f...-xlncskNFVEJBDgjK7y7TUQ@public.gmane.org> wrote:> On Jan 18, 2008, at 6:11 PM, Glenn Gentzke wrote: > > > defonline? > > seen_at && seen_at < 20.minutes.ago > > end > > > def active? > > online? && seen_at < 5.minutes.ago > > end > > Oh, I thought because of the code that the first "sentence" was kind > of a joke, but looks like it was not :-). > > If a user just did a request you certainly want to consider him to be online, right? > > $ script/console > Loading development environment (Rails 2.0.2) > >> seen_at = Time.now > => Fri Jan 18 18:25:30 +0100 2008 > >> seen_at > 5.minutes.ago > => true > > 5.minutes.ago marks a point past in time. A user isonlineif it has > been seen *recently*, so seen_at has to be greater than what you > consider to be recent enough. Note that ">" is defined such that today > > yesterday. > > -- fxn--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I follow a similar approach myself though I generally leave the session model alone. May I suggest a possible improvement. It can reduce the SQL Update frequency if you only update say every 5 minutes. This can be done in the before_filter or in the SQL statement, whichever you prefer. Cheers, -- Long http://FATdrive.tv/wall/trakb/10-Long http://FATdrive.tv/ ----- Original Message ----- From: <william.harding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> To: "Ruby on Rails: Talk" <rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org> Sent: Monday, January 28, 2008 4:24 PM Subject: [Bulk] [Rails] Re: "What users are online?" function> > I recently wrote a follow up to Matt Beedle''s blog on my own blog: > http://www.williambharding.com/blog/?p=99 > > A couple differences between his approach and mine: > > * I added fields to the session model itself to avoid the Marshalling/ > Unmarshalling to find a specific attribute within the session > * He doesn''t discuss exactly how (or if) he goes about updating which > users have been seen when. I discuss how I did it with a before > filter that does one SQL Update statement, which is about as efficient > as possible > * My query for users online is scoped such that it only returns the > fields I need (using a :select), and it limits the number of users > returned > > Generally speaking, I needed a solution that performs as well as > possible, since it will be called extremely often (both to update when > a user was seen and to find which users have been seen recently). I > think that the solution I came up with ought to fit the bill pretty > well, though I''d welcome any comments if others have tweaks to my > approach. > > Bill > > On Jan 18, 9:31 am, Xavier Noria <f...-xlncskNFVEJBDgjK7y7TUQ@public.gmane.org> wrote: > > On Jan 18, 2008, at 6:11 PM, Glenn Gentzke wrote: > > > > > defonline? > > > seen_at && seen_at < 20.minutes.ago > > > end > > > > > def active? > > > online? && seen_at < 5.minutes.ago > > > end > > > > Oh, I thought because of the code that the first "sentence" was kind > > of a joke, but looks like it was not :-). > > > > If a user just did a request you certainly want to consider him to be online, right? > > > > $ script/console > > Loading development environment (Rails 2.0.2) > > >> seen_at = Time.now > > => Fri Jan 18 18:25:30 +0100 2008 > > >> seen_at > 5.minutes.ago > > => true > > > > 5.minutes.ago marks a point past in time. A user isonlineif it has > > been seen *recently*, so seen_at has to be greater than what you > > consider to be recent enough. Note that ">" is defined such that today > > > yesterday. > > > > -- fxn > --~--~---------~--~----~------------~-------~--~----~--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---