在Rails中手动设置updated_at
我正在将我的旧博客post迁移到我的新Rails博客中,我希望他们的updated_at
属性与我旧博客上的相应值相匹配(而不是他们迁移到我的新Rails博客的日期)。
我怎样才能做到这一点? 当我手动设置updated_at
,它会被before_save
回调覆盖。
注意:此问题仅对Rails <3.2.11有效。 较新版本的Rails允许您手动设置时间戳,而不会覆盖它们。
如果它是一次性的话,你可以打开或关闭record_timestamps
。
ActiveRecord::Base.record_timestamps = false #set timestamps manually ActiveRecord::Base.record_timestamps = true
当我用我的应用程序遇到这个问题时,我搜索了一下,这似乎对我来说最有意义。 这是一个初始化程序,我可以在需要的地方调用:
module ActiveRecord class Base def update_record_without_timestamping class << self def record_timestamps; false; end end save! class << self def record_timestamps; super ; end end end end end
从最新版本的Rails(根据iGEL评论3.2.11)开始,您可以在代码中设置updated_at属性,保存时将更改更改。
我假设rails跟踪手动更改的“脏”属性,而不是在保存时覆盖。
> note = Note.last Note Load (1.4ms) SELECT "notes".* FROM "notes" ORDER BY "notes"."id" DESC LIMIT 1 => # > note.updated_at = 2.years.ago => Sun, 07 Jul 2013 21:20:47 UTC +00:00 > note.save (0.4ms) BEGIN (0.8ms) UPDATE "notes" SET "updated_at" = '2013-07-07 21:20:47.972990' WHERE "notes"."id" = 39 (0.8ms) COMMIT => true > note => #
如此简短的回答,在最新版本的rails中不再需要解决方法。
我接受了Andy的回答并对其进行了修改以接受块:
module ActiveRecord class Base def without_timestamping class << self def record_timestamps; false; end end yield class << self remove_method :record_timestamps end end end end
这是Andy Gaskell的回答:
class ActiveRecord::Base class_inheritable_writer :record_timestamps def do_without_changing_timestamps self.class.record_timestamps = false yield ensure self.class.record_timestamps = true end end
解决方案是暂时将ActiveRecord :: Base.record_timestamps设置为false:
ActiveRecord::Base.record_timestamps = false # Make whatever changes you want to the timestamps here ActiveRecord::Base.record_timestamps = true
如果你想要一个更强大的解决方案,你可能想尝试像mrm建议的那样:
module ActiveRecord class Base def self.without_timestamping timestamping = self.record_timestamps begin self.record_timestamps = false yield ensure self.record_timestamps = timestamping end end end end
然后,您可以轻松地对模型进行更改,而无需自动更新时间戳:
ActiveRecord::Base.without_timestamping do foo = Foo.first bar = Bar.first foo.updated_at = 1.month.ago bar.updated_at = foo.updated_at + 1.week foo.save! bar.save! end
或者,如果您只想更新特定类中的记录而不加时间戳:
module ActiveRecord class Base # Don't delete Rail's ActiveRecord::Base#inherited method self.singleton_class.send(:alias_method, :__inherited__, :inherited) def self.inherited(subclass) __inherited__ # Adding class methods to `subclass` class << subclass def without_timestamping # Temporarily override record_timestamps for this class class << self def record_timestamps; false; end end yield ensure class << self remove_method :record_timestamps end end end end end end
例如:
Foo.without_timestamping do foo = Foo.first bar = Bar.new(foo: foo) foo.updated_at = 1.month.ago foo.save! # Timestamps not automatically updated bar.save! # Timestamps updated normally end
或者您可以使用类似于Venkat D.建议的方法,该方法基于每个实例:
module ActiveRecord class Base def without_timestamping class << self def record_timestamps; false; end end yield ensure class << self remove_method :record_timestamps end end end end
例如:
foo = Foo.first foo.without_timestamping do foo2 = Foo.new(parent: foo) foo.updated_at = 1.month.ago foo.save! # Timestamps not automatically updated foo2.save! # Timestamps updated normally end
我看到两种方法可以轻松实现这一目标:
触摸(Rails 5)
在Rails 5中,您可以使用touch
方法并提供命名参数time
如触摸文档中所述
foo.touch(time: old_timestamp)
update_column(Rails> = 3.1)
如果你想在Rails 4及更低版本中使用它或想要避免所有回调,你可以使用update_column
或update_columns
方法之一绕过所有安全或触摸回调和validation
foo.update_column(updated_at, old_timestamp)
要么
foo.update_columns(updated_at: old_timestamp)
- validation和测试Rails 3关联的完美方法(使用RSpec / Remarkable)?
- ActionController :: RoutingError(UserAccountsController的未定义方法`load_and_authorize_resource’:Class):
- 活动管理员:如何设置页面标题?
- 如何显示个别列表? Ruby on Rails
- 太阳黑子返回模型的所有结果
- 无需密码即可更新`User`属性
- 如何在Ruby on Rails中将数组持久化到数据库?
- Rails 3使用has_many belongs_to关联构建一个select标记
- 堆栈级别太深,尝试从3.0更新到3.1