2013-08-18 31 views
3

在我的Rails应用程序中,我想记录一个userlast_seen的时间。如何在Rails应用程序中记录上次活动的时间?

现在,我这样做,因为在我的SessionsHelper如下:

def sign_in(user) 
    ..... 
    user.update_column(:last_seen, Time.zone.now) 
    self.current_user = user 
end 

但是,这不是很精确,因为用户可能会在上午8点和晚上的last_seen数据库列登录仍将包含时间。

所以我想只要用户采取动作来更新last_seen

class ApplicationController 
    before_filter :update_last_seen 

    private 

    def update_last_seen 
    current_user.last_seen = Time.zone.now 
    current_user.save 
    end 
end 

但我不喜欢这种做法是因为数据库中获取并在每一个用户采取措施打击。

那么有什么可能是更好的选择呢?

回答

9

Rails的居然有这种行为的内置有touch

User.last.touch 
#=> User's updated_at is updated to the current time 

它需要在任何精心调配DB来处理更新这样一个列应该是远远低于5毫秒的时间,并且很可能在1ms以下。假设你已经建立了数据库连接(或者,在Rails的情况下,使用先前建立的池中的连接),开销可以忽略不计。


要回答你的代码是否是慢,好了,你想这一切都错了你的问题。您可以优化已经非常快速的性能表现,但我反而更关心“正确性”。这里是的ActiveRecord的touch方法的实现:

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 

现在你告诉我,这是更快?哪个是更正确

在这里,我给你一个提示:成千上万的人已经使用touch这个实现,这个代码很可能已经运行了数百万次。您的代码已被您单独使用,可能甚至没有编写测试,也没有任何同行评审。

“但是,仅仅因为别人使用它,并不会使它在经验上更好,”你争辩说。当然,你是对的,但它又错过了一点:当你可以继续构建你的应用程序并让其他人类(你的用户)可以使用并从中受益时,你就会在这里旋转你的轮子,想知道什么是更好的尽管一个好的解决方案已经被其他人得到了。

为了在棺材中留下一个钉子,是的,你的代码更慢。它执行回调,进行脏跟踪,并将所有更改的属性保存到数据库。 touch绕过了这一切,专注于完成将时间戳更新持久化到模型所需的工作。

+0

+1:听起来像是过早优化 –

+0

好,很好。不知道。但是在文档中它说'touch'更新数据库中的'updated_at'字段。如果我想更新另一个字段,比如说'last_seen'字段怎么办?我上面发布的代码会比'touch'方法慢吗?我假设这两种方法都会以某种方式触及数据库。 – Tintin81

+0

@ Tintin81你应该仔细看看那个文档。 http://apidock.com/rails/ActiveRecord/Persistence/touch – coreyward

相关问题