Reputation: 6571
I have a website where I need to be able to display on each user's profile the last time they were "active" on the site. In this case, "active" is defined by browsing content, interacting with other users and completing courses.
My plan is to have a last_active
column on the Users table, which I can update with Time.now
. The question is, how do I do this without hitting up the database during every single controller action? That seems... expensive. For example, I want to avoid doing this:
# In each controller
def index
current_user.activity
end
# In the User model
def activity
self.update_attribute(:last_active, Time.now)
end
Because then every time a user gets the content listing, I have to make a database call.
The other option would be to have an Activity table, which I update with various user actions (kind of like audits). That would allow me to store and display more relevant information about what users are doing. But that goes back to the same question: how do I update these tables without massive overhead?
Upvotes: 3
Views: 989
Reputation: 173
If you're fine with async updates, you could set up a delayed resque job, deleting previous jobs.
Resque.remove_delayed_selection RecordLastUserActivity, {
|args| args[0]['user_id'] == current_user.id
}
Resque.enqueue_at(10.minutes.from_now, RecordLastUserActivity,
user_id: current_user.id, last_seen_at: Time.now)
Not sure if this will provide greater perfomance though, it will require some testing.
Upvotes: 0
Reputation: 844
Don't you think about redis|memcache|any_in_memory_storage for such data?
Upvotes: 0
Reputation: 11
I don't think there is a way around the overhead without restricting when you update a particular user's 'last active' attribute.
So as Charlie Egan alluded to, you have two options:
Only update the 'last active' attribute when the user logs in. You'll still get a decent sense of a user's general activity on the site just by doing this.
Or
Only update the 'last active' attribute on certain activity. For example, you mentioned in your question that users can complete courses. That seems like a fairly significant 'activity', so update the 'last active' attribute. Less significant activities, like browsing content can be ignored.
Upvotes: 1
Reputation: 2183
It's really a rather moot question – No, there is no way to update the database without updating the database.
If you wanted to get complicated, you could try to do some client-side scripting to store that information in a session variable or a cookie, and only commit it to the db once in a while, but that seems like a lot of work for a small feature.
Maybe if you add an index to your :last_active
column you make it marginally less expensive? But otherwise, I would just go for it, and try to be conservative about how often it's updated.
You could also check if Time.now > @user.last_active+10.minutes
before updating to make sure that you aren't constantly writing to the db, but then your just querying instead which may not be better...
Upvotes: 2