Diabetes in Fiction
A catalogue of novels in which at least one character has diabetes. 218 books so far, each with a plot summary and a note on how the diabetes is handled.
diabetesinfiction.com

screenshot taken 2026-08-30 · open diabetesinfiction.com
at a glance
- what
- A searchable catalogue of fiction with diabetic characters, with reader submissions
- stack
- Rails 8 (Ruby 4) · Inertia.js · React 19 + TypeScript · Tailwind v4 · Vite, server‑rendered
- search
- Typesense with facets and sorting; falls back to SQL automatically if Typesense is away
- data
- Postgres for everything, including Solid Cache, Queue and Cable; covers in Active Storage
- auth
- Cookie sessions for a handful of editors; no public sign‑up. Readers never sign in
- runs as
- One image on Coolify, plus a Typesense container; moved to the new host 2026‑08‑30
What it does
Every book on the site has at least one character with diabetes. Each entry carries the authors in the order they appear on the cover, the cover itself, genre, age group, the type of diabetes, the publication year, a plot summary, and a short account of how the condition is represented in the story, which is what a reader with diabetes actually wants to know before picking it up. There are 218 so far.
Readers can search and filter by any of those facets, sort by newest added or by title, and open a book’s page for the full details. Two forms are open to anyone without an account: suggest a book and report a problem with the site. Both save to the database no matter what, and if a Discord webhook is configured a job posts each one to a channel so I see it the same day. The submissions queue itself is a signed‑in page.
How it’s built
This is the second home for the collection: the original site was rebuilt from scratch as a
Rails 8 app. The request flow is the part worth explaining because it is not the usual Rails
shape. A controller action sets instance variables and never calls render. A shared parent
controller auto‑renders by finding an Alba resource class named after the action, which
serialises those variables into props. Inertia hands the props to a React page component
that mirrors the controller and action by file path, and Vite renders it server‑side first.
Adding a page means adding both halves; one without the other renders nothing.
Typed route helpers for the front end are generated from config/routes.rb by Typelizer, so
a renamed route fails type‑checking rather than 404ing in production.
Search has one entry point used by both the results and the facet counts. When Typesense
is configured and reachable it does the faceting, filtering and sorting. If the key is
missing, the container is down, or it raises anything at all, the same call falls back to an
ActiveRecord scope with LIKE text search and facet counts computed by hand, and tells the
front end that search is degraded. Indexing happens after each book saves, and an indexing
failure is logged rather than allowed to fail the save. Search never takes the site down.
Author order is deliberate: the join table carries a position, and book.authors reads
through it sorted, while the raw association stays unordered so bulk queries and filters keep
working. It is a small thing that was wrong once.
Data
Postgres everywhere, including the three Solid adapters for cache, job queue and websockets, each on its own database because they ship as schema dumps rather than migrations and silently skip loading if they share the primary. Covers are Active Storage attachments with a pre‑warmed thumbnail variant. Books join to authors, genres, age groups, diabetes types and publication years; suggestions and site issues are their own small tables.
Auth
There is no Devise and no public sign‑up. A signed cookie carries a session token; the application controller requires a session by default and public pages opt out explicitly, in a way that still populates the current user for anyone who happens to be signed in. Editor accounts are created from the Rails console.
Deploy and operations
Built into one image and deployed on Coolify with the Typesense container beside it. Outgoing mail (Resend) and Typesense are both optional at boot and degrade to a no‑op mailer and SQL search rather than crashing. CI runs RuboCop, Brakeman, bundler‑audit and RSpec against a real Postgres, and type‑checks the front end.
This is the one site here with an audience that isn’t me, which is why it got the search fallback and the submission forms before it got anything pretty.