Cia
Central Internal Auditing: Audit model events like update/create/delete + attribute changes + grouped them by transaction, in normalized table layout for easy query access.
Install / Use
/learn @grosser/CiaREADME
Central Internal Auditing
Audit model actions like update/create/destroy/<custom> + 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<br/>
michael@grosser.it<br/>
License: MIT<br/>
Related Skills
node-connect
352.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
111.1kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
352.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
352.0kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
