Versioning
All Futures can keep a complete history of every saved change to your model. Versioning is opt-in, per class:
class Draft < AllFutures::Base
enable_versioning!
attribute :body, :string
endHow it works
Every save that actually changes the record appends a new version to the model's history and increments current_version. Saving a record with no changes is a no-op: nothing is written and no version is created.
draft = Draft.create(body: "first")
draft.current_version # => 1
draft.update(body: "second")
draft.current_version # => 2
draft.save # no changes
draft.current_version # => 2Version history survives round trips through Redis:
found = Draft.find(draft.id)
found.current_version # => 2
found.version(1).attributes["body"] # => "first"
found.version(2).attributes["body"] # => "second"Accessing versions
current_versionreturns the current version number, ornilfor non-versioned modelsversion(n)returns aVersionstruct withattributesandupdated_at; raisesAllFutures::VersionNotFoundfor unknown versionsversionsreturns the raw version hash, keyed by version number
Skipping versioning
Use without_versioning to save changes without recording a version:
You can also toggle versioning on an instance with disable_versioning! and enable_versioning!.
Optimistic locking
Versioned models are protected against concurrent updates. If another process saves a newer version after you loaded your copy, your save raises AllFutures::RecordStale instead of silently clobbering their changes:
Rescue RecordStale to implement retry or merge behavior. Saving a stale copy that has no changes of its own is a harmless no-op.
By default the version check and the write are not atomic — two processes can both pass the check in a tight race and the later SET wins. Treat the default as a guard rail.
Atomic locking (optional)
For apps that need a real compare-and-set, flip the app-wide switch:
Or outside Rails:
When enabled, versioned saves run a single Redis Lua script that reads current_version, compares it to the value you loaded, and either SETs the new snapshot or returns stale. One round trip, no lost updates between the check and the write. Non-versioned models are unaffected (last write still wins). Default is false.
Storage notes
Versions are stored inside the same Redis JSON document as the record itself, so history grows without bound as you save. For long-lived, frequently updated models, consider whether you need versioning enabled, or reach for without_versioning on high-frequency writes.
Last updated
Was this helpful?