2011-02-03 111 views
38

我该如何做到这一点?如何在不触摸updated_at属性的情况下更新单个属性?

试图建立2种方法,称为

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 

和关闭使用回调,比如开时间戳:

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

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

有什么建议吗?我不想为了统计页面数量而创建另一个表格。

+0

尝试使用`update_attributes!(:pagehit => pagehit + 1)`并查看是否有任何错误。顺便说一句,你是否在这里粘贴了`def disable_timestamps`两次,或者你的代码是否一样? – Zabba 2011-02-03 15:02:01

+0

[有没有办法避免自动更新Rails时间戳字段?](http://stackoverflow.com/questions/861448/is-there-a-way-to-avoid-automatically-updating-rails-timestamp场地) – 2016-05-12 18:46:30

回答

12

如果所有你想要做的是增加一个计数器,我会用increment_counter方法来代替:

ModelName.increment_counter :pagehit, id 
85

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

update_attribute跳过验证,但会触碰updated_at并执行回调。

update_column跳过验证,不碰updated_at,并且不执行回调。

因此,如果您不想影响updated_at并且不需要回调,那么update_column是一个不错的选择。

查看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 
2

为了避免Monkeypatchingtroubles你也可以使用ModelName.update_all用于此目的:

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

这还没有触及记录的时间戳。

2

这不是一个好主意,这样做:

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

应该

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

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

-1

如果精度是不是真的那么重要,你不要指望代码运行很多次,你可以尝试改变保存在数据库中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替换它。

1

你也有decrementincrement(和他们的爆炸版本)不会改变updated_at,不要去触发验证回调,并显然很方便的计数器/整数。

相关问题