Обновите один столбец до значения другого в миграции Rails - PullRequest
64 голосов
/ 07 марта 2011

У меня есть таблица в приложении Rails с сотнями тысяч записей, и у них есть только отметка времени created_at. Я добавляю возможность редактировать эти записи, поэтому я хочу добавить отметку времени updated_at в таблицу. В моей миграции для добавления столбца я хочу обновить все строки, чтобы новый updated_at совпадал со старым created_at, поскольку это значение по умолчанию для вновь создаваемых строк в Rails. Я мог бы сделать find(:all) и просмотреть записи, но это заняло бы часы из-за размера таблицы. Что я действительно хочу сделать, это:

UPDATE table_name SET updated_at = created_at;

Есть ли лучший способ сделать это при миграции на Rails с использованием ActiveRecord вместо выполнения необработанного SQL?

Ответы [ 6 ]

114 голосов
/ 08 марта 2011

Я бы создал миграцию

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> ...")
20 голосов
/ 07 марта 2011

Вы можете использовать update_all , который работает очень похоже на необработанный SQL.Это все варианты, которые у вас есть.

Кстати, лично я не уделяю так много внимания миграции.Иногда сырой SQL - действительно лучшее решение.Обычно код миграции не используется повторно.Это однократное действие, поэтому я не беспокоюсь о чистоте кода.

10 голосов
/ 20 августа 2015

Как писал Грегдан, вы можете использовать update_all. Вы можете сделать что-то вроде этого:

Model.where(...).update_all('updated_at = created_at')

Первая часть - ваш типичный набор условий. В последней части рассказывается, как выполнять задания. Это даст оператор UPDATE, по крайней мере, в Rails 4.

0 голосов
/ 24 июня 2019

Вы можете напрямую запустить следующую команду для вашего 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")

0 голосов
/ 25 марта 2019

Это общий способ решения без необходимости написания запроса, поскольку запросы подвергаются риску.

  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
0 голосов
/ 07 марта 2011

Как разовая операция, я бы просто сделал это в rails console. Это действительно займет часы? Может быть, если есть миллионы записей ...

records = ModelName.all; records do |r|; r.update_attributes(:updated_at => r.created_at); r.save!; end;`
...