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

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

我引入了一些遗留数据,我希望从遗留数据字段中的相应值设置这些值。我发现,当我在模型上设置它们,然后保存模型时,Rails 似乎覆盖了传入的值。

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

39596 次浏览

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

ActiveRecord::Base.record_timestamps = false

或者可以使用 update _ all:

Update _ all (更新,条件 = 零,选项 = {})

根据给定的详细信息更新所有记录 如果它们符合一系列条件 供应,限制和订单也可以 此方法构造一个 单个 SQL UPDATE 语句并发送 - 直接进入数据库-是的 不实例化所涉及的模型 它不会触发活动记录 复试。

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

  1. 使用 legacy_created_atlegacy_updated_at字段创建模型。
  2. 加载遗留数据。根据需要映射到模型字段。您可以使用 #save,通常不用担心使用 update_all或类似的方法,如果需要,还可以使用回调。
  3. 创建迁移以将列重命名为 created_atupdated_at

在迁移或 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.

跳过验证。

没有回复。

如果该列可用,则不更新 update _ at/update _ on 列。

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

如果不在批量导入中,您可以重写 should _ record _ time 戳吗?方法添加新的检查,以检查何时更新 update _ at 列。

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

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

(情境: 在迁移中修改 create _ at 属性)

Rails 5提供了一种方便的方法来更新记录,而无需更新它的时间戳 updated_at: https://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

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

我不能让 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

取自 给你

这对于 rake 任务非常有用,因为您必须覆盖深度相关模型的某些属性,并且不希望为内部回调操心,而您的用户依赖于 created_atupdated_at属性或者那些用作排序列的属性。

我已经迟到了,但这就是我们跳过更新 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