Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manually set updated_at in Rails

I'm migrating my old blog posts into my new Rails blog, and I want their updated_at attribute to match the corresponding value on my old blog (not the date they were migrated into my new Rails blog).

How can I do this? When I set updated_at manually it gets overridden by the before_save callback.

Note: This question is only valid for Rails < 3.2.11. Newer versions of Rails allow you to manually set timestamps without them being overwritten.

like image 785
Tom Lehman Avatar asked Sep 06 '09 19:09

Tom Lehman


3 Answers

If it's a one time thing you can turn record_timestamps on or off.

ActiveRecord::Base.record_timestamps = false

#set timestamps manually

ActiveRecord::Base.record_timestamps = true

When I ran into this issue with my app, I searched around for a bit and this seemed like it made the most sense to me. It's an initializer that I can call where I need to:

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  
like image 157
Andy Gaskell Avatar answered Nov 13 '22 16:11

Andy Gaskell


As of recent versions of Rails (3.2.11 as per iGELs comment) you can set the updated_at property in code and the change will be honoured when saving.

I assume rails is keeping track of 'dirty' properties that have been manually changed and not overwriting on save.

> note = Note.last
  Note Load (1.4ms)  SELECT "notes".* FROM "notes" ORDER BY "notes"."id" DESC LIMIT 1
=> #<Note id: 39, content: "A wee note", created_at: "2015-06-09 11:06:01", updated_at: "2015-06-09 11:06:01">
> 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
=> #<Note id: 39, content: "A wee note",  created_at: "2015-06-09 11:06:01", updated_at: "2013-07-07 21:20:47">

So short answer, workarounds are not needed any longer in recent versions of rails.

like image 40
pauliephonic Avatar answered Nov 13 '22 15:11

pauliephonic


I see two ways to accomplish this easily:

touch (Rails >=5)

In Rails 5 you can use the touch method and give a named parameter time like described in the documentation of touch

foo.touch(time: old_timestamp)

update_column (Rails >=4)

If you want it in Rails 4 and lower or want to avoid all callbacks you could use one of the update_column or update_columns methods which bypass all safe or touch callbacks and validations

foo.update_column(updated_at, old_timestamp)

or

foo.update_columns(updated_at: old_timestamp)
like image 5
Sandro L Avatar answered Nov 13 '22 17:11

Sandro L