ActsAsCalculatorEditor

A mountable Rails engine providing a Hotwire UI for authoring acts_as_calculator formulas and templates — CRUD, live validation preview, and JSON export. No permissions layer; wire the engine's current_owner and route constraints to your host app's auth as needed.

This gem never duplicates the core gem's persistence or calculation logic — every write goes through acts_as_calculator's own service objects (PublishFormulaVersion, PublishTemplate, ImportLookupTable, etc.), called in-process rather than over HTTP. See docs/core-gem-contract.md for the full contract this gem is built against.

Installation

Add both gems (this one is not yet published, so a path or git reference is required until it is):

gem "acts_as_calculator"
gem "acts_as_calculator_editor"

Mount the engine:

# config/routes.rb
mount ActsAsCalculatorEditor::Engine => "/calculator-editor"

Pin Lexxy in your host's importmap (this gem does not do it for you, since a host may use a different JS bundler):

# config/importmap.rb
pin "lexxy"
// app/javascript/application.js
import "lexxy"

Run acts_as_calculator's own install generator if you haven't already — this engine reads and writes its tables directly, it ships no migrations of its own.

The two editors

  • Templates (format: "html") use Lexxy — a real rich text editor, since template bodies are genuinely prose/HTML meant for a payslip, invoice, or policy document.
  • Formula expressions deliberately do not use Lexxy. A Dentaku expression like salary - (salary * federal_2026) is not prose, and Lexxy's editor value is HTML even in "plain" mode — an expression using < without a following space (salary <bonus) gets parsed as the start of an HTML tag and silently truncated, producing a shorter expression that still parses as valid Dentaku but computes something different. See docs/lexxy-decision.md for the full investigation, including a rejected markdown-based workaround. The formula editor is a plain textarea with a Stimulus-driven syntax-highlighting overlay and live validation instead.

A note on Lexxy and Rails version

lexxy requires Rails ≥ 8.0.2, and this gemspec's floors match that — it cannot install against Rails 7.1/7.2 even though acts_as_calculator itself supports those versions. Lexxy also unconditionally touches ActionText at boot on Rails 8.0/8.1 (a to_prepare hook), regardless of whether any view in your app renders rich text — this gem requires action_text/engine itself to guarantee that's loaded, but if your host app hand-picks railties rather than requiring rails/all, be aware Action Text (and transitively, Active Storage) will load as a result of installing this gem.

Lexxy also sets config.lexxy.override_action_text_defaults = true on Rails 8.0/8.1, which aliases rich_text_area to its own helper globally — if your host app has its own Action Text fields and doesn't want them swapped to Lexxy, set that config to false yourself. This gem doesn't set it (a third gem changing a host-level setting silently would be worse than the problem).

Export / import

GET /export produces the same JSON document shape acts_as_calculator's own generator/rake task import, with ?key=, ?scope=, ?full_history=, and ?disposition= query params — see docs/core-gem-contract.md for the exact shape and the deliberate differences from the core gem's API response serializers. There is no import UI yet; use the core gem's own rails generate acts_as_calculator:import or POST /import (if enable_api is on) to bring a document back in.

Development

bundle install
bundle exec rspec
bundle exec rubocop

The dummy app lives at spec/dummy and builds its schema by running acts_as_calculator's own install-generator migration, so an upstream column rename shows up as a red spec here rather than silent drift.

See docs/ for the full integration contract and the Lexxy decision writeup, and .claude/ for the harness (agents + skills) that built this gem — read CLAUDE.md for the pointer and change log.