如何在不触摸updated_at属性的情况下更新单个属性?

我怎样才能做到这一点?

试图创build2个方法,称为

def disable_timestamps ActiveRecord::Base.record_timestamps = false end def enable_timestamps ActiveRecord::Base.record_timestamps = true end 

和更新方法本身:

 def increment_pagehit update_attribute(:pagehit, pagehit+1) end 

打开和closures时间戳使用callback如:

 before_update :disable_timestamps, :only => :increment_pagehit after_update :enable_timestamps, :only => :increment_pagehit 

但它没有更新任何东西,甚至没有更新所需的属性(pagehit)。

有什么build议? 我不想创build另一个表来计算页面访问量。

有没有办法避免自动更新Rails的时间戳字段?

或者接近你的问题:

http://blog.bigbinary.com/2009/01/21/override-automatic-timestamp-in-activerecord-rails.html

作为update_attribute的替代方法,在Rails 3.1中,您可以使用update_column

update_attribute跳过validation,但会触及updated_at并执行callback。

update_column跳过validation,不会触及updated_at ,并且不执行callback。

因此,如果您不想影响updated_at并且不需要callback,则update_column是一个很好的select。

有关更多信息,请参阅http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html

另请注意, update_column将更新内存模型中属性的值,并且不会被标记为脏。 例如:

 p = Person.new(:name => "Nathan") p.save p.update_column(:name, "Andrew") p.name == "Andrew" # True p.name_changed? # False 

如果你想要做的只是增加一个计数器,我会使用increment_counter方法:

 ModelName.increment_counter :pagehit, id 

为了避免Monkeypatchingtroubles,你也可以使用ModelName.update_all来达到这个目的:

 def increment_pagehit self.class.update_all({ pagehit: pagehit+1 }, { id: id }) end 

这也不会触及logging上的时间戳。

这样做不是一个好主意:

 self.class.update_all({ pagehit: pagehit+1 }, { id: id }) 

它应该是

 self.class.update_all("pagehit = pagehit + 1", { id: id }) 

原因是如果两个请求是并行的,那么在第一个版本中,两个请求都会使用相同的编号来更新pagehits,因为它使用保存在Ruby内存中的编号。 第二个选项使用sql服务器将数字增加1,如果两个查询同时发生,服务器将一个接一个地处理它们,最终会得到正确的页面数量。

你也有decrementincrement (和他们的爆炸版本)不会改变updated_at ,不去触发validationcallback,显然是方便的计数器/整数。

如果精度不是真的那么重要,而且你也不希望代码运行很多次,那么你可以尝试改变数据库中保存的updated_at值,如下所示:

 u = User.first u.name = "Alex 2" # make some changes... u.updated_at = u.updated_at + 0.000001.second # alter updated_at u.save 

所以Rails实际上会尝试保存相同的值,而不是用Time.nowreplace它。