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

如果您有DB列created_atupdated_at当您创build和更新模型对象时,Rails将自动设置这些值。 有没有办法保存模型,而不触摸这些列?

我正在引入一些遗留数据,我想从遗留数据字段(不同名称)的相应值中设置这些值。 我发现当我在模型上设置它们,然后保存模型,Rails似乎覆盖了传入的值。

当然,我可以用不同的方式命名Rails模型列来防止这种情况,但是在导入数据之后,我希望Rails能够自动完成时间戳记的工作。

在迁移或rake任务中执行此操作(如果您处于边缘导轨上,则在新的数据库种子中 ):

 ActiveRecord::Base.record_timestamps = false begin run_the_code_that_imports_the_data ensure ActiveRecord::Base.record_timestamps = true # don't forget to enable it again! end 

您可以安全地设置created_atupdated_at手动,Rails不会抱怨。

注意:这也适用于单个模型,例如User.record_timestamps = false

改用update_column方法:

http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column

 update_column(name, value) # Updates a single attribute of an object, without calling save. 

validation被跳过。

callback被跳过。

如果该列可用,updated_at / updated_on列不会更新。

在新对象上调用时引发ActiveRecordError,或者当name属性标记为只读时引发。

您可以在迁移中设置以下内容:

 ActiveRecord::Base.record_timestamps = false 

或者等待使用update_all:

update_all(updates,conditions = nil,options = {})

更新所有logging与给定的细节,如果他们符合一组条件提供,限制和订单也可以提供。 这个方法构造一个单独的SQL UPDATE语句,并直接发送到数据库。 它不会实例化相关模型,也不会触发Active Recordcallback。

Rails 5提供了一种更新logging而不更新其时间戳updated_at的方便方法。

你只需要在更新logging时通过touch:false

 >> user = User.first >> user.updated_at => Thu, 28 Apr 2016 20:01:57 IST +05:30 >> user.name = "Jose" >> user.save(touch: false) => true >> user.updated_at => Thu, 28 Apr 2016 20:01:57 IST +05:30 

在Rails 3+中,对于单个对象,请为对象而不是类设置record_timestamps 。 也就是说,

 >> user = User.first >> user.updated_at => Tue, 12 Apr 2016 22:47:51 GMT +00:00 >> user.name = "Jose" => "Jose" >> user.record_timestamps = false >> user.save => true >> user.updated_at => Tue, 12 Apr 2016 22:47:51 GMT +00:00 >> User.record_timestamps => true 

通过这种方式,您不会触摸模型的全局状态,也不必记住在ensure块中恢复之前的设置。

由于这是一次性导入,因此您可以执行以下操作:

  1. 使用legacy_created_atlegacy_updated_at字段创build模型。
  2. 加载遗留数据。 根据需要映射到模型字段。 你可以使用#save ,一般不用担心使用update_all之类的,如果需要的话可以使用callback。
  3. 创build一个迁移,将列重命名为created_atupdated_at

不在批量导入时,可以覆盖should_record_timestamps? 方法在您的模型上添加新的检查何时更新updated_at列。

我喜欢使用混合模块暂时closures块中的时间戳:

 module WithoutTimestamps def without_timestamps old = ActiveRecord::Base.record_timestamps ActiveRecord::Base.record_timestamps = false begin yield ensure ActiveRecord::Base.record_timestamps = old end end end 

那么你可以在任何需要的地方使用它

 class MyModel < ActiveRecord::Base include WithoutTimestamps def save_without_timestamps without_timestamps do save! end end end 

或者只是这样的一次性的:

 m = MyModel.find(1) WithoutTimestamps.without_timestamps do m.save! end 

参考其他答案,我发现令我惊讶的是,禁用单个模型的时间戳,如下所示:

 User.record_timestamps = false 

为我的开发数据库工作,但不是在我的预生产数据库,它运行在不同的服务器上。 但是,如果我禁用所有模型的时间戳,它的工作原理

 ActiveRecord::Base.record_timestamps = false 

(情况:在迁移中修改created_at属性)

或者,为了线程安全,请参阅: http : //www.hungryfools.com/2007/07/turning-off-activerecord-timestamp.html