1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>Guided Rails</title> 7 <meta name="description" content="Accessibility and testing in Rails."> 8 <link rel="icon" href="/favicon.png" type="image/png" sizes="32x32"> 9 <link rel="icon" href="/favicon.svg" type="image/svg+xml"> 10 <link type="application/atom+xml" rel="alternate" href="https://guidedrails.com/feed.xml" title="Guided Rails" /> 11
11<script src="https://cdn.tailwindcss.com?plugins=typography"></script>
11 12
12<script> 13 tailwind.config = { 14 theme: { 15 extend: { 16 colors: { 17 brand: "#7a1f5c" 18 } 19 } 20 } 21 } 22 </script>
22 23 24
24<script src="https://cdn.usefathom.com/script.js" data-site="FLESYFAW" defer></script>
24 25 26 <link rel="stylesheet" href="/assets/css/syntax.css"> 27 <link rel="stylesheet" href="/assets/css/main.css"> 28</head> 29<body class="bg-white text-gray-900 antialiased flex min-h-screen flex-col"> 30 <header class="border-t-8 border-brand"> 31 <div class="mx-auto flex w-[min(100vw_-_3rem,80rem)] items-center justify-between py-6"> 32 <a href="/" class="flex items-center gap-2 text-lg font-semibold tracking-tight text-brand"> 33 <svg aria-hidden="true" viewBox="0 4 64 44" class="h-7 w-auto" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"> 34 <path d="M6 44 A26 26 0 0 1 12.1 27.3 L11 8 L23.1 19.6 A26 26 0 0 1 40.9 19.6 L53 8 L51.9 27.3 A26 26 0 0 1 58 44"/> 35 <circle cx="23" cy="28" r="1.6" fill="currentColor" stroke="none"/> 36 <circle cx="41" cy="28" r="1.6" fill="currentColor" stroke="none"/> 37 <path d="M28.5 33 H35.5 L38 36 L32 42 L26 36 Z" fill="currentColor"/> 38 <path d="M26 36 H38 M28.5 33 L30.5 36 L32 42 M35.5 33 L33.5 36 L32 42" stroke="#fff" stroke-opacity="0.55" stroke-width="1"/> 39 <path d="M2 34 L14 36 M2 41 L14 40 M62 34 L50 36 M62 41 L50 40" stroke-width="2"/> 40 </svg> 41 Guided Rails 42 </a> 43 <nav class="flex gap-6 text-sm text-gray-600"> 44 <a href="/blog/" class="hover:text-gray-900">Blog</a> 45 </nav> 46 </div> 47 </header> 48 <main class="flex-1 w-full max-w-2xl mx-auto px-6 py-16"> 49 <section class="relative left-1/2 mb-16 w-[min(100vw_-_3rem,80rem)] -translate-x-1/2"> 50 <h1 class="max-w-3xl text-4xl font-semibold tracking-tight md:text-5xl">Rails apps that are easy to change, test, and use.</h1> 51 <p class="mt-6 max-w-2xl text-lg text-gray-600"> 52 Cleaner code, fast and reliable tests, accessible views, and practices your team keeps after we're gone. That matters more now that AI writes so much of your code, because it can only copy the patterns you already have. 53 </p> 54 <a href="mailto:[email protected]" class="mt-8 inline-block rounded-md bg-brand px-4 py-2 text-white hover:bg-brand/90">Get in touch</a> 55</section> 56 57<section class="relative left-1/2 mb-16 w-[min(100vw_-_3rem,80rem)] -translate-x-1/2"> 58 <h2 class="text-lg font-medium">Services</h2> 59 <p class="mt-2 text-gray-600"> 60 Hands-on help for Rails teams. 61 </p> 62 <div class="mt-6 grid gap-6 md:grid-cols-2"> 63 <div class="flex min-w-0 flex-col rounded-lg border border-gray-200 p-6"> 64 <h3 class="text-base font-medium">Codebase cleanup</h3> 65 <p class="mt-2 text-gray-600"> 66 We take over messy Rails apps and get them back into shape: refactoring tangled code, fixing slow and flaky test suites, making the app accessible, and setting the practices your team follows from then on. That matters more now that AI writes so much of the code, because AI can only follow the patterns your codebase already has. 67 </p> 68 <div class="mt-auto flex flex-wrap gap-3 pt-4 text-sm"> 69 <a href="mailto:[email protected]?subject=Codebase%20cleanup" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">Get in touch</a> 70 </div> 71 </div> 72 <div class="flex min-w-0 flex-col rounded-lg border border-gray-200 p-6"> 73 <h3 class="text-base font-medium">Accessibility audits</h3> 74 <p class="mt-2 text-gray-600"> 75 We review your Rails app against WCAG with a keyboard and a screen reader, then hand you a prioritized list of fixes pointing at the views and components that need them. 76 </p> 77 <div class="mt-auto flex flex-wrap gap-3 pt-4 text-sm"> 78 <a href="mailto:[email protected]?subject=Accessibility%20audit" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">Get in touch</a> 79 </div> 80 </div> 81 </div> 82</section> 83 84<section class="relative left-1/2 mb-16 w-[min(100vw_-_3rem,80rem)] -translate-x-1/2"> 85 <h2 class="text-lg font-medium">Projects</h2> 86 <p class="mt-2 text-gray-600"> 87 Rails apps we've built and run ourselves. 88 </p> 89 <div class="mt-6 grid gap-6 md:grid-cols-2"> 90 <div class="flex min-w-0 flex-col rounded-lg border border-gray-200 p-6"> 91 <h3 class="text-base font-medium">Catberry</h3> 92 <p class="mt-2 text-gray-600"> 93 The front porch for roots music. Catberry helps players and listeners find jams, concerts, and circles near them, and the artists, bands, and organizations that keep the music alive. 94 </p> 95 <div class="mt-auto flex flex-wrap gap-3 pt-4 text-sm"> 96 <a href="https://catberry.io" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">catberry.io</a> 97 </div> 98 </div> 99 <div class="flex min-w-0 flex-col rounded-lg border border-gray-200 p-6"> 100 <h3 class="text-base font-medium">Null Squatch</h3> 101 <p class="mt-2 text-gray-600"> 102 Walk around, and the app proves where Bigfoot is <em>not</em>. Every mile you cover shrinks the map of places he could still be hiding. 103 </p> 104 <div class="mt-auto flex flex-wrap gap-3 pt-4 text-sm">
105 <a href="https://nullsquatch.com" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">nullsquatch.com</a> 106 </div> 107 </div> 108 <div class="flex min-w-0 flex-col rounded-lg border border-gray-200 p-6"> 109 <h3 class="text-base font-medium">Banjos & Bigfoot</h3> 110 <p class="mt-2 text-gray-600"> 111 A blog and podcast about roots music and America's greatest resident. Fiddle tunes, banjo breaks, and the occasional sighting. 112 </p> 113 <div class="mt-auto flex flex-wrap gap-3 pt-4 text-sm"> 114 <a href="https://banjosandbigfoot.com" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">banjosandbigfoot.com</a> 115 </div> 116 </div> 117 </div> 118</section> 119 120<section class="relative left-1/2 mb-16 w-[min(100vw_-_3rem,80rem)] -translate-x-1/2"> 121 <h2 class="text-lg font-medium">Gems</h2> 122 <p class="mt-2 text-gray-600"> 123 Small, focused gems we've built for our own Ruby projects and shared with everyone. 124 </p> 125 <div class="mt-6 grid gap-6 md:grid-cols-2"> 126 <div class="flex min-w-0 flex-col rounded-lg border border-gray-200 p-6"> 127 <h3 class="font-mono text-base font-medium">a11y-lint</h3> 128 <p class="mt-2 text-gray-600"> 129 Catch accessibility issues in ERB and Phlex views before they ship, like images without alt text and links or buttons without an accessible name. 130 </p> 131 <div class="prose prose-sm mt-4 max-w-none"> 132 133<figure class="highlight"><pre><code class="language-console" data-lang="console"><span class="gp">$</span><span class="w"> </span>a11y-lint app/views 134<span class="go">app/views/home.html.erb:3 [ImgMissingAlt] img tag is missing an alt attribute (WCAG 1.1.1) 1351 offense found</span></code></pre></figure> 136 137 </div> 138 <div class="mt-auto flex flex-wrap gap-3 pt-4 text-sm"> 139 <a href="https://github.com/Guided-Rails/a11y-lint" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">GitHub</a> 140 <a href="https://rubygems.org/gems/a11y-lint" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">RubyGems</a> 141 <a href="https://a11y-lint.guidedrails.com/" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">Documentation</a> 142 </div> 143 </div> 144 <div class="flex min-w-0 flex-col rounded-lg border border-gray-200 p-6"> 145 <h3 class="font-mono text-base font-medium">minitest-attributes</h3> 146 <p class="mt-2 text-gray-600"> 147 Assert several attributes of an object in one call, with a clear failure message for each mismatch. 148 </p> 149 <div class="prose prose-sm mt-4 max-w-none"> 150 151<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">assert_attributes</span> <span class="n">person</span><span class="p">,</span> 152 <span class="ss">first_name: </span><span class="s2">"Marceline"</span><span class="p">,</span> 153 <span class="ss">nickname: </span><span class="kp">nil</span><span class="p">,</span> 154 <span class="ss">created_at: </span><span class="no">Time</span><span class="p">.</span><span class="nf">current</span></code></pre></figure> 155 156 </div> 157 <div class="mt-auto flex flex-wrap gap-3 pt-4 text-sm"> 158 <a href="https://github.com/Guided-Rails/minitest-attributes" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">GitHub</a> 159 <a href="https://rubygems.org/gems/minitest-attributes" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">RubyGems</a> 160 </div> 161 </div> 162 <div class="flex min-w-0 flex-col rounded-lg border border-gray-200 p-6"> 163 <h3 class="font-mono text-base font-medium">guarda</h3> 164 <p class="mt-2 text-gray-600"> 165 Authorization built around controller actions, not models. Each controller gets a policy, and each action gets a policy method. 166 </p> 167 <div class="prose prose-sm mt-4 max-w-none"> 168 169<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">PostsController</span> <span class="o"><</span> <span class="no">ApplicationController</span> 170 <span class="k">def</span> <span class="nf">update</span> 171 <span class="n">authorize</span> <span class="vi">@post</span> <span class="c1"># => PostsPolicy#update?</span> 172 <span class="k">end</span> 173<span class="k">end</span></code></pre></figure> 174 175 </div> 176 <div class="mt-auto flex flex-wrap gap-3 pt-4 text-sm"> 177 <a href="https://github.com/Guided-Rails/guarda" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">GitHub</a> 178 <a href="https://rubygems.org/gems/guarda" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">RubyGems</a> 179 </div> 180 </div> 181 <div class="flex min-w-0 flex-col rounded-lg border border-gray-200 p-6"> 182 <div class="flex items-center gap-3"> 183 <h3 class="font-mono text-base font-medium">bridgetown-stoa</h3>
184 <span class="rounded-full border border-gray-300 px-2 py-0.5 text-xs text-gray-600">Pre-alpha</span> 185 </div> 186 <p class="mt-2 text-gray-600"> 187 A documentation theme for Bridgetown, inspired by just-the-docs. 188 </p> 189 <div class="prose prose-sm mt-4 max-w-none"> 190 191<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="nn">---</span> 192<span class="na">layout</span><span class="pi">:</span> <span class="s">bridgetown-stoa/layout</span> 193<span class="na">title</span><span class="pi">:</span> <span class="s">My Page</span> 194<span class="nn">---</span></code></pre></figure> 195 196 </div> 197 <div class="mt-auto flex flex-wrap gap-3 pt-4 text-sm"> 198 <a href="https://github.com/Guided-Rails/bridgetown-stoa" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">GitHub</a> 199 <a href="https://rubygems.org/gems/bridgetown-stoa" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">RubyGems</a> 200 <a href="https://www.npmjs.com/package/bridgetown-stoa" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">npm</a> 201 </div> 202 </div> 203 <div class="flex min-w-0 flex-col rounded-lg border border-gray-200 p-6"> 204 <div class="flex items-center gap-3"> 205 <h3 class="font-mono text-base font-medium">axe-cuprite</h3> 206 <span class="rounded-full border border-gray-300 px-2 py-0.5 text-xs text-gray-600">Archived</span> 207 </div> 208 <p class="mt-2 text-gray-600"> 209 Run axe-core accessibility checks in Capybara system tests driven by Cuprite, with readable RSpec matchers. 210 </p> 211 <div class="prose prose-sm mt-4 max-w-none"> 212 213<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">expect</span><span class="p">(</span><span class="n">page</span><span class="p">).</span><span class="nf">to</span> <span class="n">be_axe_clean</span><span class="p">.</span><span class="nf">checking_only</span><span class="p">(</span><span class="ss">:color_contrast</span><span class="p">)</span></code></pre></figure> 214 215 </div> 216 <div class="mt-auto flex flex-wrap gap-3 pt-4 text-sm"> 217 <a href="https://github.com/Guided-Rails/axe-cuprite" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">GitHub</a> 218 <a href="https://rubygems.org/gems/axe-cuprite" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">RubyGems</a> 219 </div> 220 </div> 221 <div class="flex min-w-0 flex-col rounded-lg border border-gray-200 p-6"> 222 <div class="flex items-center gap-3"> 223 <h3 class="font-mono text-base font-medium">uthmani_text_size</h3> 224 <span class="rounded-full border border-gray-300 px-2 py-0.5 text-xs text-gray-600">Archived</span> 225 </div> 226 <p class="mt-2 text-gray-600"> 227 Count the letters in Uthmani Arabic text, ignoring the diacritics and marks that <code>String#size</code> counts as separate characters. 228 </p> 229 <div class="prose prose-sm mt-4 max-w-none"> 230 231<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="s2">"Ù±ÙØ±ÙÙØÙÙ ÙÙ°ÙÙ"</span><span class="p">.</span><span class="nf">size</span> <span class="c1"># => 12</span> 232<span class="s2">"Ù±ÙØ±ÙÙØÙÙ ÙÙ°ÙÙ"</span><span class="p">.</span><span class="nf">uthmani_size</span> <span class="c1"># => 6</span></code></pre></figure> 233 234 </div> 235 <div class="mt-auto flex flex-wrap gap-3 pt-4 text-sm"> 236 <a href="https://github.com/Guided-Rails/uthmani_text_size" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">GitHub</a> 237 <a href="https://rubygems.org/gems/uthmani_text_size" class="rounded-md border border-gray-300 px-3 py-1.5 hover:border-gray-900 hover:text-gray-900">RubyGems</a> 238 </div> 239 </div> 240 </div> 241</section> 242 243 </main> 244 <footer class="border-t-8 border-brand">
245 <div class="mx-auto flex w-[min(100vw_-_3rem,80rem)] justify-between gap-6 py-8 text-sm text-gray-600"> 246 <span>© 2026 Guided Rails, LLC. All rights reserved.</span> 247 <nav class="flex gap-6"> 248 <a href="/accessibility/" class="hover:text-gray-900">Accessibility</a> 249 <a href="/license/" class="hover:text-gray-900">License</a> 250 <a href="/privacy/" class="hover:text-gray-900">Privacy</a> 251 </nav> 252 </div> 253 </footer> 254</body> 255</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.