ActiveRecord 更新系


Rails のバージョンは 1.2.3 を想定。
基本的に断りがない場合は ActiveRecord::Base のインスタンスメソッドまたはクラスメソッドについての話である。


1. 基本的に更新は save で行う


save と save! の違い


save : 失敗したら false を返す。
save!: 失敗したら RecordInvalid 例外を投げる。


Dave Thomas 「Rails によるアジャイル Web アプリケーション開発」によると、この2つの使い分けは、


save: コントローラのアクションメソッドとして呼び出されることを想定。エラーを画面に表示することを考えると、例外を投げるのはまずいので true/false を返す。
save!: バッチ的な処理で使うべき。


とのこと。


2. update_attribute メソッドとは?


update_attribute(:title, "entry2title_modified")
とすると、直接 この属性の変化をデータベースに書き込む。
実際には update_attribute() で指定しなかった属性も同時に
DB 更新されるらしい。


実際ソースコードを見ると、


# File lib/active_record/base.rb, line 1584
def update_attribute(name, value)
send(name.to_s + '=', value)
save
end


となっていて、単純に save しているだけだとわかる。


3. 楽観的ロック


たとえば、同じレコードを2人のユーザが同時に更新用画面で表示して、それぞれデータベースを更新する、というケースはときどき起こりうる。こんなときに、各自がそれぞれ更新してしまうと、一方で行われた更新が失敗してしまう。


こんなとき、更新するときに、すでに他のプロセスが更新していないかチェックし、更新されていたら、エラーとするやり方を「楽観的ロック」と呼ぶそうだ。


Rails の場合 lock_version という int 型のカラムをテーブルに追加するだけで、Rails は「ああ、楽観的ロックをかけたいんだな」と判断して自動的にやってくれる。


具体的には、テーブル上の lock_version と レコードオブジェクトの lock_version を比べて、同じだったら、更新するときに lock_version を + 1 する。違っていたらエラーとする。


一定時間、すべてのレコードに対する他のプロセスによるアクセスを禁止する悲観的ロックにくらべると、確かに仕組みは単純ながら、スループットも落ちないし、いいやり方だな。どうせ、同時に書き込むことはまずないしね。(構成管理ツールの CVS は楽観的ロックなのに対して、SourceSafe は悲観的ロックなわけだな)


4. 削除


クラスメソッド系(delete / delete_all / destroy_all ) とインスタンスメソッド系(destroy)の2つがある。


(1) クラスメソッド系


delete(Integer or Array) # id を指定
delete_all(conditions = nil) # conditions は find() の conditions と同じもの
destroy_all(conditions = nil)


delete_all と destroy_all の違いは、delete_all はいきなりごそっと DB からレコードを削除するのに対して、 destroy_all はコールバックを呼び出すということ。(これもネタ元は「Web アプリケーション開発」)


(2) インスタンスメソッド系


これは簡単。
たとえば、article.destory とやれば articles テーブルの該当レコードが削除される。