Обновить один столбец для значения другого в миграции Rails
У меня есть таблица в приложении Rails с сотнями тысяч записей, и у них есть только метка created_at
. Я добавляю возможность редактировать эти записи, поэтому я хочу добавить временную метку updated_at
к таблице. В моей миграции для добавления столбца я хочу обновить все строки, чтобы новый updated_at
соответствовал старому created_at
, поскольку это значение по умолчанию для вновь созданных строк в Rails. Я мог бы сделать find(:all)
и перебирать записи, но это займет несколько часов из-за размера таблицы. Я действительно хочу:
UPDATE table_name SET updated_at = created_at;
Есть ли лучший способ сделать это в миграции Rails, используя ActiveRecord, а не выполнять необработанный SQL?
Ответы
Ответ 1
Я бы создал миграцию
rails g migration set_updated_at_values
и внутри его напишите что-нибудь вроде:
class SetUpdatedAt < ActiveRecord::Migration
def self.up
Yourmodel.update_all("updated_at=created_at")
end
def self.down
end
end
Таким образом вы достигаете двух вещей
- это повторяемый процесс, при каждом возможном развертывании (при необходимости) он выполняется
- Это эффективно. Я не могу думать о более рубическом решении (это так же эффективно).
Примечание. Вы также можете запустить raw sql внутри миграции, если запрос становится слишком сложным для записи с использованием activerecord. Просто напишите следующее:
Yourmodel.connection.execute("update your_models set ... <complicated query> ...")
Ответ 2
Вы можете использовать update_all, который очень похож на исходный SQL. Это все варианты, которые у вас есть.
Я лично не обращаю внимания на миграцию. Иногда raw SQL - действительно лучшее решение. Обычно код миграции не используется повторно. Это однократное действие, поэтому я не беспокоюсь о чистоте кода.
Ответ 3
Как писал gregdan, вы можете использовать update_all
. Вы можете сделать что-то вроде этого:
Model.where(...).update_all('updated_at = created_at')
Первая часть - ваш типичный набор условий. В последней части говорится, как выполнять задания. Это приведет к выражению UPDATE
, по крайней мере, в Rails 4.
Ответ 4
Это общий способ решения без необходимости написания запроса, поскольку запросы подвергаются риску.
class Demo < ActiveRecord::Migration
def change
add_column :events, :time_zone, :string
Test.all.each do |p|
p.update_attributes(time_zone: p.check.last.time_zone)
end
remove_column :sessions, :time_zone
end
end
Ответ 5
Вы можете напрямую запустить следующую команду на своей rails console
ActiveRecord::Base.connection.execute("UPDATE TABLE_NAME SET COL2 = COL1")
Например: я хочу обновить sku своей таблицы элементов с помощью remote_id таблиц элементов. команда будет выглядеть следующим образом:
ActiveRecord::Base.connection.execute("UPDATE items SET sku = remote_id")
Ответ 6
Как однократная операция, я просто сделаю это в rails console
. Это займет несколько часов? Может быть, если есть миллионы записей...
records = ModelName.all; records do |r|; r.update_attributes(:updated_at => r.created_at); r.save!; end;`