如果您有数据库列created_at
,updated_at
那么在创建和更新模型对象时,Rails会自动设置这些值。有没有一种方法可以保存模型而不接触那些列?
我要引入一些旧数据,我想从(不同名称)旧数据字段中的相应值中设置这些值。我发现在模型上设置它们然后保存模型时,Rails似乎会覆盖传入的值。
当然,我可以使用不同的命名方式来命名Rails模型列,以防止这种情况,但是在导入数据之后,我希望Rails执行其自动时间戳记功能。
Answers:
在迁移或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
true
即使在控制台内执行脚本或代码时,我们是否还需要将其重置回?
使用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
update
。您需要将其分为两个操作,如下所示。
您可以在迁移过程中设置以下内容:
ActiveRecord::Base.record_timestamps = false
或交替使用update_all:
update_all(更新,条件=无,选项= {})
如果所有记录与提供的一组条件相匹配,则使用给定的详细信息更新所有记录,也可以提供限制和订单。此方法构造单个SQL UPDATE语句,并将其直接发送到数据库。它不会实例化所涉及的模型,也不会触发Active Record回调。
在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
块中还原先前的设置。
我喜欢使用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
提到其他答案,令我惊讶的是,禁用了单个模型的时间戳,例如:
User.record_timestamps = false
适用于我的开发数据库,但不适用于在其他服务器上运行的预生产数据库。但是,如果我禁用所有型号的时间戳,它将起作用
ActiveRecord::Base.record_timestamps = false
(情况:在迁移中修改created_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任务非常有用,在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
def without_timestamps old = ActiveRecord::Base.record_timestamps ActiveRecord::Base.record_timestamps = false begin yield ensure ActiveRecord::Base.record_timestamps = old end end