我们最近开始在我们的公司推动合规性,并且需要保留对当前在 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
记录的时间,但不会触发删除before_destroy
a的时间。RunwayModel
我的问题是......有没有办法让它工作,以便它观察这些变化(和/或可能的其他删除)?
是否有更好的解决方案仍然相对不引人注目?