Attach meta information to events
Table of contents
In auditable systems, what happened is only part of the story — you also need to know who did it and in what context. Event metainformation lets you attach that context to every event that you record during a request. That enriches your audit trail with the provenance required for compliance, debugging, and forensic analysis.
Generate the initializer
Funes ships a generator that creates a pre-configured initializer with the metainformation options already commented in:
$ bin/rails generate funes:initializer
This command creates config/initializers/funes.rb with the event_metainformation_attributes and event_metainformation_validations blocks ready to uncomment and fill in. Funes exposes the attributes you declare there on Funes::EventMetainformation, an ActiveSupport::CurrentAttributes subclass that gives you thread-isolated, per-request storage. Rails resets it between requests, and it is safe under any multithreaded server such as Puma.
Define attributes
You configure metainformation in your application’s initializer. Start by declaring the attributes you need:
# config/initializers/funes.rb
Funes.configure do |config|
config.event_metainformation_attributes = [:user_id, :action, :git_version]
end
These become thread-safe attributes on Funes::EventMetainformation; Funes attaches them automatically to every event that it persists during the same request.
Attributes don’t take a type — they keep whatever Ruby value you assign. Integers stay integers, strings stay strings, nil is allowed. Funes serializes the whole hash into the event’s meta_info JSON column when the event lands, so any JSON-compatible value survives ipsis literis.
Add validations
Use the event_metainformation_validations block to enforce that the required context is always present when you record an event:
# config/initializers/funes.rb
Funes.configure do |config|
config.event_metainformation_attributes = [:user_id, :action, :git_version]
config.event_metainformation_validations do
validates :user_id, presence: true
validates :action, presence: true, format: { with: /\A\w+#\w+\z/ }
validates :git_version, presence: true, format: { with: /\A[a-f0-9]{7,40}\z/ }
end
end
The block DSL supports all standard ActiveModel validators. If metainformation fails validation at append time, Funes raises Funes::InvalidEventMetainformation and rolls back the database transaction.
Set values per request
Funes doesn’t care how you set the values — only that they’re in place before an append runs. Anything that assigns to Funes::EventMetainformation during the request works: a before_action, middleware, a service object called from the controller, even a manual assignment inside the action itself.
What follows is one suggestion that fits most Rails apps: populate the attributes at the start of each request from a before_action, with a concern that keeps the wiring out of ApplicationController. Feel free to adapt it to whatever shape your app already uses.
# app/controllers/concerns/events_metainformation_attachment.rb
module EventsMetainformationAttachment
extend ActiveSupport::Concern
included do
before_action :set_event_metainformation
end
private
def set_event_metainformation
Funes::EventMetainformation.user_id = current_user&.id
Funes::EventMetainformation.action = "#{controller_name}##{action_name}"
Funes::EventMetainformation.git_version = ENV["GIT_VERSION"]
end
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
include EventsMetainformationAttachment
end
Every event that you append during that request will carry the values from this before_action.