Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a full Audit log in Rails for every table?

Tags:

We recently began a compliance push at our company and are required to keep a full history of changes to our data which is currently managed in a Rails application. We've been given the OK to simply push something descriptive for every action to a log file, which is a fairly unobtrusive way to go.

My inclination is to do something like this in ApplicationController:

around_filter :set_logger_username

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

Then create an observer that looks something like this:

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

and in general this works great, but it fails when using the "magic" <association>_ids method that is tacked to has_many :through => associations.

For instance:

# 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

This will end up triggering the after_create when new Runway records are associated, but will not trigger the before_destroy when a RunwayModel is deleted.

My question is... Is there a way to make it work so that it will observe those changes (and/or potentially other deletes)?
Is there a better solution that is still relatively unobtrusive?

like image 248
Mark S. Avatar asked Mar 04 '10 16:03

Mark S.


People also ask

What is the difference between audit log and event log?

IT devices across your network create logs based on events. Audit logs are records of these event logs, typically regarding a sequence of activities or a specific activity. Audit logs don't always operate in the same way. In fact, they vary significantly between devices, applications, and operating systems.

What is audit log rails?

Audit logs are a set of records that document the changes made to other data in a system, along with the user who made those changes, and the time those changes were made.

What is the difference between audit and logging?

The difference is more in usage than in technique. Auditing is used to answer the question "Who did what?" and possibly why. Logging is more focussed on what's happening.


1 Answers

I had a similar requirement on a recent project. I ended using the acts_as_audited gem, and it worked great for us.

In my application controller I have line like the following

audit RunWay,RunWayModel,OtherModelName

and it takes care of all the magic, it also keeps a log of all the changes that were made and who made them-- its pretty slick.

Hope it helps

like image 129
Jonathan Avatar answered Oct 21 '22 17:10

Jonathan