ActiveRecord Model Versioning: A Proposal for ActiveVersion

11 November 2025, Helsinki, Åndrei Makarov

ActiveRecord versioning and internationalization have followed similar paths in the Ruby ecosystem: start simple with JSON or YAML storage in database columns, then struggle with the limitations. JSONB is fun at the start, but becomes painful when you need to query, maintain, or extend functionality. YAML has no native PostgreSQL support. Neither approach scales well for complex requirements like custom attributes, attachments, rich text, or versioning by platform or user role.

I'm proposing a new gem called active_version (with the ActiveVersion module) that takes a different approach: proper schema design with separate tables for versions, a DSL for building relations and automations, and extensibility as a first-class concern. This post explores the design, requirements, and seeks feedback from the community.

The Core Problem

Most versioning and i18n gems in Ruby store data as JSON, YAML, or hstore in database columns. This approach has fundamental limitations:

The better approach is to have a proper schema—a table schema copy to separate _translations or _versions tables. This provides:

Gem Proposal: ActiveVersion

The active_version gem (with the ActiveVersion module) would provide a common pattern for versioning with a DSL for building relations and automations between the main record and version records. Extensions and specific functionality could be delivered as separate gems:

Use Cases

1. Internationalization (i18n)

Locale versions of models and attributes. Each translation is a version indexed by locale, allowing proper querying and maintenance of multilingual content.

2. Versioning and Auditing

Soft-delete, drafts, and logging changes. Versions can be indexed by time, user, or any other dimension. Full object tracking with support for associations and related records.

3. Context-Based Versioning

Different versions for different needs: versioning by platform (web, mobile, API), by user role, by A/B test variant, or any other contextual dimension.

Requirements

Any proposed solution must meet these requirements:

Current Solutions Analysis

audited

Has a good codebase and clean schema, but:

paper_trail

Most used versioning gem, but:

hoardable

Also uses whodunnit (problematic), but:

Design Principles

Separate Tables, Not Columns

Each versioned model gets a corresponding _versions table with the same schema as the main table, plus version-specific metadata (version number, index, timestamps, etc.). This allows:

Index-Based Version Access

Versions should be accessible by index—locale, datetime, string ID, or any other dimension. Console users should be able to fetch versions easily:

article.version(locale: 'en')
article.version(at: 1.week.ago)
article.version(platform: 'mobile')

DSL for Relations and Automations

A clean DSL for defining version relationships and automatic behaviors:

class Article < ApplicationRecord
  has_versions do
    index_by :locale
    index_by :created_at
    auto_create_draft: true
    track_associations: [:comments, :tags]
  end
end

Extensibility Through Composition

Core functionality in active_version, with extensions as separate gems that compose cleanly:

# Gemfile
gem 'active_version'
gem 'active_version-i18n'  # For locale-based versioning
gem 'active_version-audit' # For audit logging

Questions for the Community

I'm seeking feedback on several aspects:

Console Interface

A good console interface is crucial for maintenance. Users should be able to:

Performance Considerations

Designing for performance from the start:

Next Steps

This is a proposal and a call for feedback. If you've struggled with versioning or i18n in ActiveRecord, I'd love to hear about:

The goal is to build a solution that solves real problems with a clean, extensible design. Proper schema design, no JSON/YAML storage, and extensibility as a first-class concern.

If this resonates with your needs, or if you have feedback, please reach out. The best solutions come from understanding real-world problems.

Related Articles