如果您有数据库列created_at
和updated_at
,Rails会在您创建和更新模型对象时自动设置这些值。有没有办法保存模型而不触及那些列?
我正在引入一些遗留数据,我想从(不同命名的)遗留数据字段中的相应值设置这些值。我发现当我在模型上设置它们然后保存模型时,Rails似乎会覆盖传入的值。
当然我可以用不同的方式命名Rails模型列来防止这种情况,但是在导入数据之后,我希望Rails能够自动执行时间戳。
答案 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_at
和updated_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_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
答案 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)
由于这是一次性导入,您可以执行以下操作:
legacy_created_at
和legacy_updated_at
字段创建模型。 #save
并且通常不用担心使用update_all
等,如果需要,您可以使用回调。 created_at
和updated_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_at
或updated_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