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

时间:2009-05-14 03:40:29

标签: ruby-on-rails ruby activerecord timestamp

如果您有数据库列created_atupdated_at,Rails会在您创建和更新模型对象时自动设置这些值。有没有办法保存模型而不触及那些列?

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

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

12 个答案:

答案 0 :(得分:71)

在迁移或rake任务中执行此操作(如果您在边缘轨道上,则在the new database seeds中执行此操作):

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

答案 1 :(得分:54)

改为使用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.

跳过验证。

跳过回调。

如果该列可用,则

updated_at / updated_on列不会更新。

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

答案 2 :(得分:34)

Rails 5提供了一种更新记录的便捷方式,而无需更新记录的时间戳updated_athttps://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-save

您,只需在更新记录时传递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

答案 3 :(得分:30)

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

ActiveRecord::Base.record_timestamps = false

或者使用update_all:

  

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

     

使用给定的详细信息更新所有记录   如果他们符合一系列条件   供应,限制和订单也可以   提供。这个方法构造了一个   单个SQL UPDATE语句并发送   它直接到数据库。确实如此   没有实例化涉及的模型   并且它不会触发Active Record   回调。

答案 4 :(得分:9)

在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块中恢复之前的设置。

答案 5 :(得分:3)

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

  1. 使用legacy_created_atlegacy_updated_at字段创建模型。
  2. 加载旧数据。根据需要映射到模型字段。您可以使用#save并且通常不用担心使用update_all等,如果需要,您可以使用回调。
  3. 创建迁移以将列重命名为created_atupdated_at

答案 6 :(得分:3)

我喜欢使用mixin模块暂时关闭一个块中的时间戳:

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

答案 7 :(得分:2)

如果不是批量导入,您可以覆盖should_record_timestamps?模型上的方法,用于添加有关何时更新updated_at列的新检查。

答案 8 :(得分:2)

参考其他答案,我惊讶地发现,禁用单个模型的时间戳,例如:

User.record_timestamps = false

适用于我的开发数据库,​​但不适用于在不同服务器上运行的预生产数据库。但是,如果我使用

禁用所有模型的时间戳,它会起作用
ActiveRecord::Base.record_timestamps = false

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

答案 9 :(得分:1)

答案 10 :(得分:1)

我无法使ActiveRecord::Base.record_timestamps标志改变任何东西,唯一的工作方法是使用ActiveRecord::Base.no_touching {}

ActiveRecord::Base.no_touching do
  Project.first.touch  # does nothing
  Message.first.touch  # does nothing
end

Project.no_touching do
  Project.first.touch  # does nothing
  Message.first.touch  # works, but does not touch the associated project
end

来自here

这对于瑞克任务非常有用,在瑞克任务中,用户必须依赖created_atupdated_at属性时,您必须重写与深度相关的模型的某些属性,并且不想打扰内部回调或用作排序列。

答案 11 :(得分:0)

我参加聚会很晚,但这是我们跳过在商店中更新updated_at的方式:

# config/initializers/no_timestamping.rb
module ActiveRecord
  class Base

    def update_record_without_timestamping
      class << self
        def record_timestamps; false; end
      end

      save!

      class << self
        remove_method :record_timestamps
      end
    end

  end
end

用法:

post.something = 'whatever'
post.update_record_without_timestamping