Files
fixin.me/CLAUDE.md
barbie-bot 4f10a4fcf8 Replace fetch() calls with Turbo form submission via requestSubmit()
setDefaultUnit and drop previously made raw fetch() requests and called
Turbo.renderStreamMessage() manually. Now both create a temporary <form>,
append hidden inputs, and call form.requestSubmit() — Turbo intercepts
the submission natively, handling CSRF, stream responses, and lifecycle.

Also document this convention in CLAUDE.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 12:45:04 +00:00

5.0 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Fixin.me is a "quantified self" Rails 7.2.3 application for personal data tracking. Users define hierarchical quantities (metrics to track), units (with optional conversion hierarchies), and readouts (individual measurements). There is also a non-persistent measurement model used as a form wrapper.

Setup

Configuration files are distributed as .dist templates — copy and customize before use:

cp config/application.rb.dist config/application.rb
cp config/database.yml.dist config/database.yml
cp config/puma.rb.dist config/puma.rb
bundle config --local frozen true
bundle config --local path .gem
bundle config --local with mysql development test   # or: pg, sqlite
bundle install
RAILS_ENV=development bundle exec rails db:create db:migrate db:seed

Common Commands

bundle exec rails s                                          # start server
bundle exec rails test                                       # all unit/model/controller tests
bundle exec rails test:system                                # all system tests (Capybara + Selenium)
bundle exec rails test test/system/units_test.rb            # single test file
bundle exec rails test --seed 64690 --name test_add_unit    # single test by name
bundle exec rails db:seed:export                             # export default settings as seed file

Architecture

Data Model

  • Quantity — hierarchical tree (self-referential parent_id). Cached depth and pathname fields are recomputed via recursive CTEs on write. Direct assignment to cached fields is blocked.
  • Unit — optional hierarchy via base_id and multiplier for unit conversion. Multiplier precision/scale is validated by a custom validator.
  • Readout — single measurement: value (IEEE 754 float), quantity, unit, category.
  • MeasurementActiveModel::Model form wrapper (not database-backed); bridges the readout creation form.
  • User — Devise-managed with a status enum: admin, active, restricted, locked, disabled. Admins can disguise as other users.

Hierarchical Queries

Both Quantity and Unit use recursive CTEs for tree traversal (ordered traversal, ancestors, progenies, common ancestors). lib/core_ext/arel/ patches Arel to support CTE with UPDATE/DELETE statements, working around Rails issue #54658.

Custom Extensions (lib/core_ext/)

  • arel/ — CTE support for UPDATE/DELETE
  • active_model/ — precision/scale validator used by Unit#multiplier
  • active_record/attr_cached mechanism (see ApplicationRecord)
  • action_view/ — record identifier suffixes
  • Miscellaneous: Array#delete_bang, BigDecimal scientific notation

Response Handling

Controllers respond to both HTML and Turbo Stream formats. Errors during Turbo Stream requests trigger a redirect with flash rather than rendering inline, handled in ApplicationController.

Numeric Precision

Readout values are stored as IEEE 754 double-precision floats (not fixed-point decimals). Rationale in DESIGN.md: biological values span many orders of magnitude; 15-digit float precision is sufficient and avoids conversion overhead.

Routes

measurements   GET/POST /measurements
readouts       GET/POST /readouts, DELETE /readouts/:id/discard
quantities     CRUD + POST /quantities/:id/reparent
units          CRUD + POST /units/:id/rebase
users          CRUD + POST /users/:id/disguise, POST /users/revert
default/       namespace for default units import/export and admin panel
root           → /units (authenticated), /sign_in (unauthenticated)

JavaScript Conventions

No manual fetch() — use Turbo

Never make AJAX requests with fetch() in JavaScript. Use Turbo's built-in mechanisms instead:

  • Links/buttons that trigger server actions: use data: {turbo_stream: true} on the element (link or button_to form).
  • Dynamic form submissions from JS (where HTML alone isn't enough): create a form element, append hidden inputs, and call form.requestSubmit(). Turbo intercepts it automatically — no manual CSRF handling, no Turbo.renderStreamMessage().
    var form = document.createElement('form');
    form.action = url; form.method = 'post'; form.dataset.turboStream = 'true';
    // append hidden inputs...
    form.addEventListener('turbo:submit-end', function() { form.remove(); });
    document.body.appendChild(form);
    form.requestSubmit();
    
  • Server-rendered HTML: use ERB partials and Turbo Stream views (*.turbo_stream.erb), never build HTML in JavaScript.

No HTML generation in JavaScript

Never use JavaScript to build and insert HTML (no innerHTML =, no createElement trees for content). Render HTML server-side in ERB partials; update the DOM via Turbo Stream actions (replace, update, append, etc.).

Database Requirements

The database must support:

  • Recursive CTEs with UPDATE/DELETE (MySQL ≥ 8.0, PostgreSQL, or SQLite3)
  • Decimal precision of 30+ digits