如何在不触摸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,如果两个查询同时发生,服务器将一个接一个地处理它们,最终会得到正确的页面数量。
你也有decrement
和increment
(和他们的爆炸版本)不会改变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.now
replace它。