Update one column to value of another in Rails migration
I have a table in a Rails app with hundreds of thousands of records, and they only have a created_at
timestamp. I'm adding the ability to edit these records, so I want to add an updated_at
timestamp to the table. In my migration to add the column, I want to update all rows to have the new updated_at
match the old created_at
, since that's the default for newly created rows in Rails. I could do a find(:all)
and iterate through the records, but that would take hours because of the size of the table. What I really want to do is:
UPDATE table_name SET updated_at = created_at;
Is there a nicer way to do that in a Rails migration using ActiveRecord rather than executing raw SQL?
I would create a migration
rails g migration set_updated_at_values
and inside it write something like:
class SetUpdatedAt < ActiveRecord::Migration
def self.up
Yourmodel.update_all("updated_at=created_at")
end
def self.down
end
end
This way you achieve two things
- this is a repeatable process, with each possible deploy (where needed) it is executed
- this is efficient. I can't think of a more rubyesque solution (that is as efficient).
Note: you could also run raw sql inside a migration, if the query gets too hard to write using activerecord. Just write the following:
Yourmodel.connection.execute("update your_models set ... <complicated query> ...")
You can use update_all which works very similar to raw SQL. That's all options you have.
BTW personally I do not pay that much attention to migrations. Sometimes raw SQL is really best solution. Generally migrations code isn't reused. This is one time action so I don't bother about code purity.