In my Rails application I would like to record the time a user
was last_seen
.
Right now, I do this as follows in my SessionsHelper
:
def sign_in(user)
.....
user.update_column(:last_seen, Time.zone.now)
self.current_user = user
end
But this is not very precise because a user might log in at 8 am and in the evening the last_seen
database column will still contain that time.
So I was thinking to update last_seen
whenever the user takes an action:
class ApplicationController
before_filter :update_last_seen
private
def update_last_seen
current_user.last_seen = Time.zone.now
current_user.save
end
end
But I don't like that approach either because the database gets hit with every action that a user takes.
So what might be a better alternative to this?
Rails actually has this sort of behavior built in with touch
:
User.last.touch
#=> User's updated_at is updated to the current time
The time it takes in any well-provisioned DB to handle updating a single column like this should be well under 5ms, and very likely under 1ms. Provided you're already going to be establishing that database connection (or, in Rails' case, using a previously established connection from a pool), the overhead is negligible.
To answer your question about whether your code is slower, well, you're thinking about this all wrong. You can optimize an already very fast operation for performance, but I instead you worry more about “rightness”. Here is the implementation of ActiveRecord's touch
method:
def touch(name = nil)
attributes = timestamp_attributes_for_update_in_model
attributes << name if name
unless attributes.empty?
current_time = current_time_from_proper_timezone
changes = {}
attributes.each do |column|
changes[column.to_s] = write_attribute(column.to_s, current_time)
end
changes[self.class.locking_column] = increment_lock if locking_enabled?
@changed_attributes.except!(*changes.keys)
primary_key = self.class.primary_key
self.class.unscoped.update_all(changes, { primary_key => self[primary_key] }) == 1
end
end
Now you tell me, which is faster ? Which is more correct ?
Here, I'll give you a hint: thousands of people have used this implementation of touch
and this very code has likely been run millions of times. Your code has been used by you alone, probably doesn't even have a test written, and doesn't have any peer review.
“But just because someone else uses it doesn't make it empirically better,” you argue. You're right, of course, but again it's missing the point: while you could go on building your application and making something other humans (your users) could use and benefit from, you are spinning your wheels here wondering what is better for the machine even though a good solution has been arrived upon by others.
To put a nail in the coffin, yes, your code is slower. It executes callbacks, does dirty tracking, and saves all changed attributes to the database. touch
bypasses much of this, focusing on doing exactly the work needed to persist timestamp updates to your models.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.