web-dev-qa-db-ja.com

コールバックを起動する必要があるときにすべてを更新する方法は?

user_idsという配列に15個のユーザーIDがあるとします。

たとえば、名前をすべて「ボブ」に変更したい場合は、次のようにします。

users = User.find(user_ids)
users.update_all( :name => 'Bob' )

ただし、これはコールバックをトリガーしません。これらのレコードの保存時にコールバックをトリガーする必要がある場合、私の知る限り、使用する唯一の方法は次のとおりです。

users = User.find(user_ids)
users.each do |u|
  u.name = 'Bob'
  u.save
end

ただし、これは、コントローラーアクションで非常に長時間実行されるタスクを意味する可能性があります。

だから、私の質問は、レコードのコールバックを実行トリガーするレコードセットへのバッチ更新をトリガーする他のより良い/より高いパフォーマンス/より便利な方法はありますか?

45
Andrew

いいえ、コールバックを実行するには、高価な操作であるオブジェクトをインスタンス化する必要があります。あなたの問題を解決する唯一の方法は、オブジェクトのインスタンス化なしでselect_allメソッドによって取得されたデータを使用できる別のメソッドにコールバックで行っているアクションをリファクタリングすることだと思います。

20
iafonov

Each/find_eachを使用する代わりに、代わりにupdateメソッドを使用してみてください:

models.update(column: value)
51
untitled

コールバックをトリガーする別の方法を次に示します。使用する代わりに

models.update_all(params)

あなたは使うことができます

models.find_each { |m| m.update_attributes(params) }

ただし、非常に大量のデータを扱う場合は、この方法はお勧めしません。
それが役に立てば幸い!

20
maxhm10