Ruby-on-rails 如何在不触及 updated_at 属性的情况下更新单个属性?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4887668/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to update a single attribute without touching the updated_at attribute?
提问by Kleber S.
How can I achieve this?
我怎样才能做到这一点?
tried to create 2 methods, called
尝试创建 2 个方法,称为
def disable_timestamps
ActiveRecord::Base.record_timestamps = false
end
def enable_timestamps
ActiveRecord::Base.record_timestamps = true
end
and the update method itself:
和更新方法本身:
def increment_pagehit
update_attribute(:pagehit, pagehit+1)
end
turn timestamps on and off using callbacks like:
使用回调打开和关闭时间戳,例如:
before_update :disable_timestamps, :only => :increment_pagehit
after_update :enable_timestamps, :only => :increment_pagehit
but it's not updating anything, even the desired attribute (pagehit).
但它没有更新任何东西,甚至是所需的属性(pagehit)。
Any advice? I don't want to have to create another table just to count the pagehits.
有什么建议吗?我不想为了计算页面点击量而创建另一个表。
采纳答案by apneadiving
回答by Nathan
As an alternative to update_attribute, In Rails 3.1+ you can use update_column.
作为替代update_attribute,在 Rails 3.1+ 中,您可以使用update_column.
update_attributeskips validations, but will touch updated_atand execute callbacks.
update_attribute跳过验证,但会触摸updated_at并执行回调。
update_columnskips validations, does not touch updated_at, and does not execute callbacks.
update_column跳过验证,不 touch updated_at,不执行回调。
Thus, update_columnis a great choice if you don't want to affect updated_atand don't need callbacks.
因此,update_column如果您不想影响updated_at并且不需要回调,这是一个不错的选择。
See http://api.rubyonrails.org/classes/ActiveRecord/Persistence.htmlfor more information.
有关更多信息,请参阅http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html。
Also note that update_columnwill update the value of the attribute in the in-memory model and it won't be marked as dirty. For example:
另请注意,update_column将更新内存模型中的属性值,并且不会将其标记为脏。例如:
p = Person.new(:name => "Nathan")
p.save
p.update_column(:name, "Andrew")
p.name == "Andrew" # True
p.name_changed? # False
回答by idlefingers
If all you're wanting to do is increment a counter, I'd use the increment_countermethod instead:
如果您想要做的只是增加一个计数器,我会改用该increment_counter方法:
ModelName.increment_counter :pagehit, id
回答by fredostarr
To avoid Monkeypatchingtroubles you could also use ModelName.update_all for this purpose:
为了避免 Monkeypatchingtroubles 你也可以为此使用 ModelName.update_all :
def increment_pagehit
self.class.update_all({ pagehit: pagehit+1 }, { id: id })
end
This also does not touch the timestamps on the record.
这也不会触及记录上的时间戳。
回答by Tom Caspy
it is not a good idea to do this:
这样做不是一个好主意:
self.class.update_all({ pagehit: pagehit+1 }, { id: id })
it should be
它应该是
self.class.update_all("pagehit = pagehit + 1", { id: id })
the reason is if two requests are parallel, on the first version both will update the pagehits with the same number, as it uses the number saved in the Ruby memory. The second option uses the sql server to increase the number by 1, in case two of these queries come at the same time, the server will process them one after the other, and will end up with the correct number of pagehits.
原因是如果两个请求是并行的,在第一个版本中,两个请求都会使用相同的数字更新页面点击量,因为它使用保存在 Ruby 内存中的数字。第二个选项使用 sql server 将数量增加 1,如果其中两个查询同时出现,服务器将一个接一个地处理它们,并最终得到正确的 pagehits 数。
回答by tirdadc
回答by glampr
If precision is not really that important, and you don't expect the code to run many times, you can try altering the saved in the database updated_atvalue, like so:
如果精度不是那么重要,并且您不希望代码运行多次,您可以尝试更改保存在数据库中的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
so that Rails will actually try to save the same value, and not replace it with Time.now.
这样 Rails 实际上会尝试保存相同的值,而不是用Time.now.

