Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to create a full Audit log in Rails for every table?
    text
    copied!<p>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.</p> <p>My inclination is to do something like this in <code>ApplicationController</code>:</p> <pre><code>around_filter :set_logger_username def set_logger_username Thread.current["username"] = current_user.login || "guest" yield Thread.current["username"] = nil end </code></pre> <p>Then create an observer that looks something like this:</p> <pre><code>class AuditObserver &lt; 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 </code></pre> <p>and in general this works <em>great</em>, but it fails when using the "magic" <code>&lt;association&gt;_ids</code> method that is tacked to has_many :through => associations.</p> <p>For instance:</p> <pre><code># model class MyModel has_many :runway_models, :dependent =&gt; :destroy has_many :runways, :through =&gt; :runway_models end #controller class MyModelController &lt; ApplicationController # ... # params =&gt; {:my_model =&gt; {:runways_ids =&gt; ['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 =&gt; "edit" } format.xml { render :xml =&gt; @my_model.errors, :status =&gt; :unprocessable_entity } end end end # ... end </code></pre> <p>This will end up triggering the <code>after_create</code> when new <code>Runway</code> records are associated, but will not trigger the <code>before_destroy</code> when a <code>RunwayModel</code> is deleted.</p> <p>My question is... Is there a way to make it work so that it will observe those changes (and/or potentially other deletes)?<br> Is there a better solution that is still relatively unobtrusive? </p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload