Railsアプリが数十万件のレコードを持ち、_created_at
_タイムスタンプしかありません。これらのレコードを編集する機能を追加するので、テーブルに_updated_at
_タイムスタンプを追加します。列を追加する移行では、すべての行を更新して、新しい_updated_at
_が古い_created_at
_と一致するようにします。 Railsで新しく作成された行。find(:all)
を実行してレコードを反復処理することもできますが、テーブルのサイズが原因で数時間かかります。
_UPDATE table_name SET updated_at = created_at;
_
Rails raw SQLを実行するのではなくActiveRecordを使用した移行でこれを行うより良い方法はありますか?
移行を作成します
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
この方法で2つのことを達成できます
注:activerecordを使用してクエリを書くのが困難になった場合、移行内でraw sqlを実行することもできます。以下を書いてください:
Yourmodel.connection.execute("update your_models set ... <complicated query> ...")
pdate_all を使用できます。これは、生のSQLと非常によく似ています。それはあなたが持っているすべてのオプションです。
ところで個人的に私は移行にそれほど注意を払いません。生のSQLが本当に最適なソリューションである場合があります。通常、移行コードは再利用されません。これは1回限りのアクションなので、コードの純度については気にしません。
Gregdanが書いたように、update_all
。次のようなことができます:
Model.where(...).update_all('updated_at = created_at')
最初の部分は、一般的な条件のセットです。最後の部分は、割り当てを行う方法を示しています。これにより、少なくともRails 4.でUPDATE
ステートメントが生成されます。
クエリはリスクにさらされるため、これはクエリを記述する必要なしに解決する一般的な方法です。
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
_Rails console
_ ActiveRecord::Base.connection.execute("UPDATE TABLE_NAME SET COL2 = COL1")
に対して次のコマンドを直接実行できます
たとえば、itemsテーブルのskuをitemsテーブルのremote_idで更新したいです。コマンドは次のようになります。ActiveRecord::Base.connection.execute("UPDATE items SET sku = remote_id")