如果您有 DB 列created_at
,updated_at
Rails 将在您创建和更新模型对象时自动设置这些值。有没有办法在不触及这些列的情况下保存模型?
我引入了一些遗留数据,我想从(不同命名的)遗留数据字段中的相应值设置这些值。我发现当我在模型上设置它们然后保存模型时,Rails 似乎覆盖了传入的值。
当然,我可以将 Rails 模型列命名为不同的名称以防止这种情况发生,但是在导入数据后,我希望 Rails 自动执行时间戳。
如果您有 DB 列created_at
,updated_at
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_at
,updated_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.
验证被跳过。
回调被跳过。
如果该列可用,updated_at/updated_on 列不会更新。
在新对象上调用或将 name 属性标记为只读时引发 ActiveRecordError。
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
您可以在迁移中设置以下内容:
ActiveRecord::Base.record_timestamps = false
或者 altenatively 使用 update_all:
update_all(更新,条件 = nil,选项 = {})
如果它们与提供的一组条件匹配,则使用给定的详细信息更新所有记录,也可以提供限制和顺序。此方法构造单个 SQL UPDATE 语句并将其直接发送到数据库。它不会实例化涉及的模型,也不会触发 Active Record 回调。
在 Rails 3+ 中,对于单个对象,record_timestamps
为对象而不是类设置。IE,
>> 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
块中恢复先前的设置。
参考其他答案,我惊讶地发现禁用单个模型的时间戳,例如:
User.record_timestamps = false
为我的开发数据库工作,但不适用于在不同服务器上运行的预生产数据库。但是,如果我禁用所有模型的时间戳,它会起作用
ActiveRecord::Base.record_timestamps = false
(情况:在迁移中修改 created_at 属性)
由于这是一次性导入,您可以执行以下操作:
legacy_created_at
使用和legacy_updated_at
字段创建模型。#save
并且通常不用担心使用update_all
等,如果需要,您可以使用回调。created_at
和updated_at
。我喜欢使用 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
当不在批量导入中时,您可以覆盖 should_record_timestamps? 模型上的方法来添加关于何时更新 updated_at 列的新检查。
我无法让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_at
或updated_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