Как создать полный журнал аудита в 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
.
Мой вопрос... Есть ли способ заставить его работать, чтобы он соблюдал эти изменения (и/или потенциально другие удаления)?
Есть ли лучшее решение, которое по-прежнему относительно ненавязчиво?
Ответы
Ответ 1
У меня было аналогичное требование по недавнему проекту. Я закончил использование acts_as_audited gem, и он отлично поработал для нас.
В моем контроллере приложений у меня есть строка, подобная следующей
audit RunWay,RunWayModel,OtherModelName
и он заботится обо всем волшебстве, он также ведет журнал всех изменений, которые были сделаны, и кто их сделал - его симпатичный slick.
Надеюсь, что это поможет
Ответ 2
Используйте плагин версий Vestal для этого:
Обратитесь к этот для получения более подробной информации. Посмотрите на аналогичный вопрос, который был недавно дан здесь.
Vestal versions
плагин является самым активным плагином, и он хранит только дельта. Дельта, принадлежащая разным моделям, хранится в одной таблице.
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
Ответ 3
Добавил этот патч обезьяны в наш 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 не вызван часто, он работает для наших нужд - хотя я собираюсь проверить act_as_versioned и act_as_audited
Ответ 4
Вы также можете использовать что-то вроде act_as_versioned http://github.com/technoweenie/acts_as_versioned
Он изменяет ваши записи в таблице и создает копию каждый раз, когда что-то изменяется (например, в вики)
Это было бы легче проверить (показать diff в интерфейсе и т.д.), Чем файл журнала