いまさら感もあるけれど・・内部を理解する
Railsレシピにも登場する、acts_as_versioned。
データを更新するたびに古いバージョンのデータを保存して、必要に応じて元に戻してくれる優れものです。
ポイントは、
class YourModel < ActiveRecord::Base
acts_as_versioned
end
で、Migrateなどで、YourModel.create_versioned_table とすると、
○ your_model_versions テーブルが生成され、
○ has_many :versions という関連が追加され、
○ YourModel::Version というクラスが実行時に動的生成される
このあたりが分かると、いろいろできます。試してみると、
> ruby script/console test --sandbox
>> m = YourModel.create(:body=>'aaaaaa')
>> m.versions
>> m.update_attribute(:body,'bbbbbb')
>> m.versions.reload
>> m.versions.last.version
>> m.versions.calculate(:max,:version) #SELECT MAX(version)を発行する
>> m.versions.first.class
>> YourModel::Version.find_by_your_model_id(m.id)
バージョニングするカラムを限定する
デフォルトでは、なんでもかんでもカラムを更新したらレコードをコピーするのですが、そんなことしてほしくないのがフツウ。あるカラムの更新だけをバージョニングの対象にしたいなら、こうなります。
class YourModel < ActiveRecord::Base
acts_as_versioned
#カラムを省く
self.non_versioned_columns << 'access_count' << 'deleted'
end
または、
class YourModel < ActiveRecord::Base
acts_as_versioned
# バージョニングする前にコールされるフックメソッド。
# true なら、バージョンを管理する。false なら、しない。
def version_condition_met?
old = YourModel::Version.find(:first,
:conditions=>"your_model_id=#{self.id}",
:order=>"version desc" )
#つまり、
#old = self.versions.last
old.nil? || self.body != old.body
end
end
::Versionにコールバックをつける
自動的に生成されるVersionクラスに、ActiveRecord::Baseの標準コールバックをくっつけてみる。キレイな形ではないけど、なかなか便利です。
バージョンレコードが増えるたびにChangeLogを通知するには(イメージ)、
class YourModel < ActiveRecord::Base
acts_as_versioned
class YourModel::Version
def after_save
YourModel.send_mail_to_you_about_changelog
end
end
def self.send_mail_to_you_about_changelog
:
end
end