我們最近開始在我們公司順應性壓,並須保持其目前在Rails應用程序管理的改變我們的數據的完整歷史。我們已經給出了可以簡單地將每個操作的描述性內容推送到日誌文件,這是一種相當不顯眼的方式。如何在每個表中爲Rails創建完整的審計日誌?
我的傾向是做這樣的事情在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
和一般工作原理偉大,但它在使用「魔術」<association>_ids
方法時,失敗了has_many: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
記錄相關聯,但是當RunwayModel
被刪除不會觸發before_destroy
。
我的問題是... 有沒有辦法使它工作,以便它會觀察到這些變化(和/或潛在的其他刪除)?
有沒有比較不顯眼的更好的解決方案?
作爲一個快速拋開,我試圖給觀察者添加一個'before_remove(可審計)',我希望什麼都不做,並且確認。此外,我們嘗試編輯'activerecord-2.3.5/lib/active_record/associations/association_collection.rb:327'並將'delete'更改爲'destroy' - 這會產生不良後果。 – 2010-03-04 17:01:01