Project

cia

0.02
Low commit activity in last 3 years
A long-lived project that still receives updates
Audit model events like update/create/delete + attribute changes + group them by transaction, in normalized table layout for easy query access.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 0
>= 0
>= 3.4
~> 1.6.0

Runtime

 Project Readme

Central Internal Auditing

Audit model actions like update/create/destroy/ + attribute changes.

  • normalized and queryable through table layout
  • actors and subjects are polymorphic
  • works on ActiveRecord 5.2+

Table layout:

Event (actor/ip/time/updated subject + message) -> has many attribute changes (changed password from foo to bar on subject)

Install

gem install cia

rails g migration add_cia + paste Migration

Then, create these two models in app/models/cia:

# app/models/cia/event.rb

module CIA
  class Event < ActiveRecord::Base
    include EventMethods
  end
end
# app/models/cia/attribute_change.rb

module CIA
  class AttributeChange < ActiveRecord::Base
    include AttributeChangeMethods
  end
end

If you’re using multiple databases, these models should inherit from an abstract class that specifies a database connection, not directly from ActiveRecord::Base.

Usage

class User < ActiveRecord::Base
  include CIA::Auditable
  audit_attribute :email, :crypted_password
end

class ApplicationController < ActionController::Base
  around_action :scope_auditing

  def scope_auditing(&block)
    CIA.audit actor: current_user, ip_address: request.remote_ip, &block
  end
end

# quick access
User.last.cia_events
changes = User.last.cia_attribute_changes
last_passwords = changes.where(attribute_name: "crypted_password").map(&:new_value)

# exceptions (raised by default)
CIA.exception_handler = -> (e) { raise e unless Rails.env.production? }

# conditional auditing
class User < ActiveRecord::Base
  audit_attribute :email, if: :interesting?

  def interesting?
    ...
  end
end

# adding an actor e.g. for user creation
CIA.current_actor = @user

# custom changes
class User < ActiveRecord::Base
  def cia_changes
    super.merge("this" => ["always", "changes"])
  end
end

# using after_commit, useful if the CIA::Event is stored in a different database then the audited class
class User < ActiveRecord::Base
  include CIA::Auditable
  audit_attribute :email, :crypted_password, callback: :after_commit
end

# passing arbitrary attributes into the .audit method
CIA.non_recordable_attributes = [:my_pretty_audit_property]
CIA.audit(actor: current_user, my_pretty_audit_property: "12345") do
  ...
end

# storing complex objects in old/new and reducing it's size if it's to big (serialized via json)
value = CIA::AttributeChange.serialize_for_storage(["some", "complex"*1000, "object"]){|too_big| too_big.delete_at(1); too_big }
CIA::AttributeChange.create!(old_value: value)

# add something to current transaction or start a new audit
CIA.audit bar: :baz, foo: :bang do
  CIA.amend_audit foo: :bar do
    puts CIA.current_transaction
  end
end
-> {foo: :bar, bar: :baz}

TODO

  • reuse AR3+ previous_changes in a nice way

Author

Michael Grosser
michael@grosser.it
License: MIT
CI