21

最近、当社でコンプライアンスの推進を開始し、現在Railsアプリケーションで管理されているデータへの変更の完全な履歴を保持する必要があります. すべてのアクションを説明するものをログ ファイルにプッシュするだけでOKです。これはかなり目立たない方法です。

私の傾向は、で次のようなことをすることですApplicationController:

around_filter :set_logger_username

def set_logger_username
  Thread.current["username"] = current_user.login || "guest"
  yield
  Thread.current["username"] = nil
end

次に、次のようなオブザーバーを作成します。

class AuditObserver < ActiveRecord::Observer
  observe ... #all models that need to be observed

  def after_create(auditable)
    AUDIT_LOG.info "[#{username}][ADD][#{auditable.class.name}][#{auditable.id}]:#{auditable.inspect}"
  end

  def before_update(auditable)
    AUDIT_LOG.info "[#{username}][MOD][#{auditable.class.name}][#{auditable.id}]:#{auditable.changed.inspect}"
  end

  def before_destroy(auditable)
    AUDIT_LOG.info "[#{username}][DEL][#{auditable.class.name}][#{auditable.id}]:#{auditable.inspect}"
  end

  def username
    (Thread.current['username'] || "UNKNOWN").ljust(30)
  end
end

一般に、これはうまく機能しますが、 has_many<association>_ids :through => 関連付けに追加された「魔法の」メソッドを使用すると失敗します。

例えば:

# model
class MyModel
  has_many :runway_models, :dependent => :destroy
  has_many :runways, :through => :runway_models
end

#controller
class MyModelController < ApplicationController

  # ...

  # params => {:my_model => {:runways_ids => ['1', '2', '3', '5', '8']}}

  def update
    respond_to do |format|
      if @my_model.update_attributes(params[:my_model])
        flash[:notice] = 'My Model was successfully updated.'
        format.html { redirect_to(@my_model) }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @my_model.errors, :status => :unprocessable_entity }
      end
    end
  end

  # ...
end

これによりafter_create、新しいRunwayレコードが関連付けられたときにトリガーされますが、削除されたbefore_destroyときにトリガーされません。RunwayModel

私の質問は...それらの変更(および/または潜在的に他の削除)を監視するように機能させる方法はありますか?
まだ比較的目立たないより良い解決策はありますか?

4

4 に答える 4

11

最近のプロジェクトでも同様の要件がありました。私はacts_as_audited gemの使用をやめましたが、うまく機能しました。

私のアプリケーションコントローラーには、次のような行があります

audit RunWay,RunWayModel,OtherModelName

すべての魔法を処理し、加えられたすべての変更とその変更者のログも保持します。

それが役に立てば幸い

于 2010-03-04T16:59:22.750 に答える
6

これにはVestalバージョンプラグインを使用します。

詳細については、このスクリーンキャストを参照してください。最近ここで答えられた同様の質問を見てください。

Vestal versionsプラグインは最もアクティブなプラグインであり、デルタのみを保存します。異なるモデルに属するデルタは、1つのテーブルに格納されます。

class User < ActiveRecord::Base
  versioned
end

# following lines of code is from the readme    
>> u = User.create(:first_name => "Steve", :last_name => "Richert")
=> #<User first_name: "Steve", last_name: "Richert">
>> u.version
=> 1
>> u.update_attribute(:first_name, "Stephen")
=> true
>> u.name
=> "Stephen Richert"
>> u.version
=> 2
>> u.revert_to(10.seconds.ago)
=> 1
>> u.name
=> "Steve Richert"
>> u.version
=> 1
>> u.save
=> true
>> u.version
=> 3
于 2010-03-04T17:37:56.227 に答える
2

このモンキーパッチを私たちに追加しましたlib/core_extensions.rb

ActiveRecord::Associations::HasManyThroughAssociation.class_eval do 
  def delete_records(records)
    klass = @reflection.through_reflection.klass
    records.each do |associate|
      klass.destroy_all(construct_join_attributes(associate))
    end
  end
end

これはパフォーマンス ヒット (!) ですが、要件を満たし、この destroy_all が頻繁に呼び出されないという事実を考慮すると、私たちのニーズには合っています。

于 2010-03-04T17:34:37.427 に答える
0

act_as_versioned http://github.com/technoweenie/acts_as_versioned
のようなものを使用することもでき ます。テーブル レコードをバージョン管理し、何かが変更されるたびにコピーを作成します (たとえば wiki のように)
。インターフェイスなど)ログファイルより

于 2010-03-04T16:58:55.007 に答える