acts_as_versionedのTips

acts_as_versionedのちょっとしたTips集。内部が分かると、けっこう自由にコールバックなどを追加できたりします。

いまさら感もあるけれど・・内部を理解する

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

コメント

コメントしてください

closed.