Недавно мы начали действовать в нашей компании и должны вести полную историю изменений наших данных, которые в настоящее время управляются в приложении 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
и в целом это работает большого, но сбой при использовании метода «magic» <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
когда RunwayModel
удаляется.
Мой вопрос ... Есть ли способ заставить его работать, чтобы он соблюдал эти изменения (и/или потенциально другие удаляет)?
Есть ли лучшее решение, которое по-прежнему относительно ненавязчиво?
как бы в стороне, я попытался добавить к наблюдателю 'before_remove (auditable)', который я ожидал ничего не делать и подтвердил. Кроме того, мы попытались отредактировать 'activerecord-2.3.5/lib/active_record/association/association_collection.rb: 327' и сменив« delete »на« destroy », что имело плохие последствия. –