Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Clinics on Rails (Brighton Ruby 2026)
Search
Alex Watt
June 25, 2026
39
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Clinics on Rails (Brighton Ruby 2026)
https://alexcwatt.com/act
https://www.youtube.com/watch?v=-PpU3xc7JJw
Alex Watt
June 25, 2026
Featured
See All Featured
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
1
280
The #1 spot is gone: here's how to win anyway
tamaranovitovic
4
1.2k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
2
2.9k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
1
450
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.6k
Building an army of robots
kneath
307
47k
For a Future-Friendly Web
brad_frost
184
10k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
930
Chasing Engaging Ingredients in Design
codingconduct
0
360
Transcript
🧑⚕ Clinics on Rails Alex Watt @alexcwatt
None
None
None
None
None
🎓 2,200 families self-supporting
None
2025 Pittsburgh Team
None
Benefits of clinical data • Set volunteer expectations • Plan
for pharmacy • Understand community health over time
Requirements doc January 2024
None
Surveyed options Throughout 2024
BackpackEMR ✅ Designed for mobile medical clinics ❌ PII stored
outside of Ethiopia, could not host in country, limited reporting
Google Sheet ✅ Free, ubiquitous, simple ❌ Relational data, limited
data validation, more difficult integrations, permissions
OpenMRS & others ✅ Powerful open source package ❌ Seemed
non-trivial to deploy and customize
It had to be simple.
None
None
Built in a week (January 2025) Monday rails new Tuesday
Finished data models Wednesday Deployed with Hatchbox Thursday User policies & launch Friday Addressed feedback
None
Project Impact • Volunteers can help with medical data •
Medical teams see their impact • Future teams are better prepared
1,583 patient encounters documented in 5 communities in Addis
Innovation Tokens acw.sh/boring
I spent only one token — on search.
Neoplasms Diseases of the blood or blood-forming organs Endocrine, nutritional,
or metabolic diseases etc.
None
Simple Hybrid Search + semantic fuzzy match
Simple Hybrid Search + semantic fuzzy match Query: fizzy sparkling
water soda frizzy hair Fizzy’s Diner
Simple Hybrid Search + informers gem (sentence-transformers) Jaro-Winkler
sentence-transformers/all-MiniLM-L6-v2 91 MB 1 vCPU and 1 GB RAM
Embedding computation MODEL_NAME = "sentence-transformers/all-MiniLM-L6-v2" EMBEDDER = Informers.pipeline("embedding", MODEL_NAME) def
embedding(text) embeddings_array = EMBEDDER.(text) Vector[*embeddings_array] end
Embedding computation MODEL_NAME = "sentence-transformers/all-MiniLM-L6-v2" EMBEDDER = Informers.pipeline("embedding", MODEL_NAME) def
embedding(text) embeddings_array = EMBEDDER.(text) Vector[*embeddings_array] end
Embeddings for diagnoses diagnoses_with_embeddings = Diagnosis.all.map do |diagnosis| text =
"#{diagnosis.name} (e.g., #{diagnosis.examples})" embedding = embedding(text) { diagnosis: diagnosis, embedding: embedding } end
Query embedding QUERY_PREFIX = "Represent this sentence for searching relevant
passages: " query_embedding = embedding(QUERY_PREFIX + query)
Search with embeddings and fuzzy text search LIMIT = 3
diagnoses_with_embeddings.filter_map do |d| semantic = cosine_similarity(query_embedding, d[:embedding]) fuzzy = fuzzy_score(query, d) semantic_relevant = semantic >= MIN_SEMANTIC_SCORE fuzzy_relevant = fuzzy >= MIN_FUZZY_SCORE next unless semantic_relevant || fuzzy_relevant [d[:diagnosis], [semantic, fuzzy].max] end.sort_by { |_, score| -score }.first(LIMIT).map(&:first)
Search with embeddings and fuzzy text search LIMIT = 3
diagnoses_with_embeddings.filter_map do |d| semantic = cosine_similarity(query_embedding, d[:embedding]) fuzzy = fuzzy_score(query, d) semantic_relevant = semantic >= MIN_SEMANTIC_SCORE fuzzy_relevant = fuzzy >= MIN_FUZZY_SCORE next unless semantic_relevant || fuzzy_relevant [d[:diagnosis], [semantic, fuzzy].max] end.sort_by { |_, score| -score }.first(LIMIT).map(&:first)
Search with embeddings and fuzzy text search LIMIT = 3
diagnoses_with_embeddings.filter_map do |d| semantic = cosine_similarity(query_embedding, d[:embedding]) fuzzy = fuzzy_score(query, d) semantic_relevant = semantic >= MIN_SEMANTIC_SCORE fuzzy_relevant = fuzzy >= MIN_FUZZY_SCORE next unless semantic_relevant || fuzzy_relevant [d[:diagnosis], [semantic, fuzzy].max] end.sort_by { |_, score| -score }.first(LIMIT).map(&:first)
None
None
What I hope you take away
#1: Your coffee ritual is (probably) weak ☕
#2: End-to-end ASAP 📅
#3: Simple software is great 👨🔧
#4: Open-weight models are awesome ✨
#5: You can just do things 💪
አመሰግናለሁ acw.sh/act