<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>Christopher Bennell</title><description>I build web stuff. Full Stack/Platform Engineering/Architecture. Senior Software Engineer.</description><link>https://cbennell.com/</link><item><title>A Tangled.org Deploy Script for Cloudflare</title><link>https://cbennell.com/posts/tangled-cloudflare-deploy/</link><guid isPermaLink="true">https://cbennell.com/posts/tangled-cloudflare-deploy/</guid><description>Deploy your static content to Cloudflare with Tangled.org CI workflows. Goodbye, GitHub Actions.</description><pubDate>Tue, 02 Jun 2026 00:00:00 GMT</pubDate></item><item><title>&quot;Every Layout&quot; Mixins</title><link>https://cbennell.com/posts/every-layout-mixins/</link><guid isPermaLink="true">https://cbennell.com/posts/every-layout-mixins/</guid><description>Every Layout is a collection of composable CSS layout patterns. Here&apos;s how I&apos;ve extracted them into a reusable pattern library I can use in any project.</description><pubDate>Wed, 04 Feb 2026 17:38:38 GMT</pubDate></item><item><title>Using Pundit in Phlex Components</title><link>https://cbennell.com/posts/using-pundit-in-phlex-components/</link><guid isPermaLink="true">https://cbennell.com/posts/using-pundit-in-phlex-components/</guid><description>Pundit&apos;s helper module makes it easy to do authorization checks in our Phlex views.</description><pubDate>Fri, 31 Oct 2025 15:40:41 GMT</pubDate></item><item><title>Site Redesign Postmortem</title><link>https://cbennell.com/posts/site-redesign-postmortem/</link><guid isPermaLink="true">https://cbennell.com/posts/site-redesign-postmortem/</guid><description>After a redesign of this site, I share some thoughts on the unexpected benefits and surprising lessons of vanilla CSS. </description><pubDate>Tue, 07 Oct 2025 04:26:46 GMT</pubDate></item><item><title>Phlex Tabs: Multiple Capture Blocks in a Phlex Component</title><link>https://cbennell.com/posts/phlex-tabs/</link><guid isPermaLink="true">https://cbennell.com/posts/phlex-tabs/</guid><description>Here&apos;s how I created a flexible interface for a Phlex component that captures multiple blocks, while maintaining backward compatibility with the simpler string-based API.</description><pubDate>Tue, 25 Mar 2025 16:20:00 GMT</pubDate></item><item><title>Honeybadger Deploy Notifications with Kamal Hooks</title><link>https://cbennell.com/posts/honeybadger-kamal-hooks/</link><guid isPermaLink="true">https://cbennell.com/posts/honeybadger-kamal-hooks/</guid><description>A solution for reporting Kamal deployments to Honeybadger using Kamal post-deploy hooks.</description><pubDate>Mon, 17 Mar 2025 16:17:00 GMT</pubDate></item><item><title>I Tried Three CSS Frameworks So You Don&apos;t Have To</title><link>https://cbennell.com/posts/three-css-frameworks/</link><guid isPermaLink="true">https://cbennell.com/posts/three-css-frameworks/</guid><description>I tested OpenProps, Bulma, and TailwindCSS while migrating to Bridgetown, and found they fall on a revealing continuum from pure CSS custom properties to all-in utility classes. Here&apos;s what I learned about each approach.</description><pubDate>Mon, 25 Nov 2024 17:13:00 GMT</pubDate></item><item><title>Bridgetown, TailwindCSS and Kamal: A Tricky Deploy Bug</title><link>https://cbennell.com/posts/bridgetown-tailwind-kamal/</link><guid isPermaLink="true">https://cbennell.com/posts/bridgetown-tailwind-kamal/</guid><description>Deploying a Bridgetown site with Kamal? Watch out for a sneaky Tailwind bug. When the jit-refresh.css file is gitignored, fresh checkouts fail silently during the build process, stripping all your Tailwind styles. Here&apos;s how to fix it with a simple esbuild plugin instead of patching your Dockerfile.</description><pubDate>Sun, 27 Oct 2024 15:44:00 GMT</pubDate></item><item><title>Migrating from Wordpress to Bridgetown</title><link>https://cbennell.com/posts/migrating-from-wordpress-to-bridgetown/</link><guid isPermaLink="true">https://cbennell.com/posts/migrating-from-wordpress-to-bridgetown/</guid><description>I&apos;ve used WordPress for many years. It no longer suits my needs as well as it used to, so I&apos;ve been investigating alternatives, inlcuding migrating this site to Bridgetown, a Ruby-based static site generator. And the switch feels principled and liberating.</description><pubDate>Sat, 26 Oct 2024 04:00:00 GMT</pubDate></item><item><title>Running WordPress Multisite on Hetzner with Custom Domains</title><link>https://cbennell.com/posts/running-wordpress-multisite-on-hetzner/</link><guid isPermaLink="true">https://cbennell.com/posts/running-wordpress-multisite-on-hetzner/</guid><description>After many years with Ionos, I finally made the switch to self-hosting on Hetzner. In this post, I walk through spinning up a VPS with WordPress preinstalled, hardening it with SSH keys and UFW, and configuring WordPress Multisite to serve multiple domains.</description><pubDate>Wed, 02 Oct 2024 04:00:00 GMT</pubDate></item><item><title>Default, Dynamic Slot Content in Rails ViewComponents</title><link>https://cbennell.com/posts/defaults-slot-content-in-rails-viewcomponents/</link><guid isPermaLink="true">https://cbennell.com/posts/defaults-slot-content-in-rails-viewcomponents/</guid><description>Ever wished your ViewComponent slots could have dynamic defaults? In this post, I show how I built an Alert component that automatically picks the right icon for its type, but can easily swap in a spinner or any custom icon with a single line of code.</description><pubDate>Wed, 25 Sep 2024 15:30:00 GMT</pubDate></item><item><title>Filtering by Association Count in Complex Models in Rails</title><link>https://cbennell.com/posts/filtering-by-association-count-in-complex-models-in-rails/</link><guid isPermaLink="true">https://cbennell.com/posts/filtering-by-association-count-in-complex-models-in-rails/</guid><description>Filtering complex associations in Rails can get tricky: built-in methods like where.associated don’t always provide efficient results. Here’s how I used a SQL subquery inside Rails scopes to make a slow page fast again.</description><pubDate>Thu, 12 Sep 2024 15:25:00 GMT</pubDate></item><item><title>Rails &quot;Disable-able&quot; Button ViewComponent / Phlex Component</title><link>https://cbennell.com/posts/rails-disable-able-button-component/</link><guid isPermaLink="true">https://cbennell.com/posts/rails-disable-able-button-component/</guid><description>Need a button that enables or disables itself in response to events? I explain how to build a reusable DisableableButton in Rails using ViewComponent (or Phlex) plus a tiny Stimulus controller—perfect for forms where you only want to allow submission once inputs are valid.</description><pubDate>Thu, 13 Jun 2024 14:31:00 GMT</pubDate></item><item><title>Building an LTI DeepLinking Response in Rails</title><link>https://cbennell.com/posts/building-an-lti-deeplinking-response-in-rails/</link><guid isPermaLink="true">https://cbennell.com/posts/building-an-lti-deeplinking-response-in-rails/</guid><description>DeepLinking lets your LTI tool send content back to the LMS—like inserting rich HTML into Canvas’s editor. This guide walks through persisting launch data, building a response form, rendering Rails views into JWTs, and even making the whole flow dynamic with Turbo.</description><pubDate>Mon, 06 May 2024 14:08:00 GMT</pubDate></item><item><title>Using Ruby Structs to Model API Responses</title><link>https://cbennell.com/posts/using-ruby-structs-to-model-api-responses/</link><guid isPermaLink="true">https://cbennell.com/posts/using-ruby-structs-to-model-api-responses/</guid><description>Here&apos;s a technique I use to model API responses in a simple class. This provides nice ergonomics with minimal boilerplate.</description><pubDate>Sun, 05 May 2024 13:59:00 GMT</pubDate></item><item><title>Handling LTI Launches in Rails</title><link>https://cbennell.com/posts/handling-lti-launches-in-rails/</link><guid isPermaLink="true">https://cbennell.com/posts/handling-lti-launches-in-rails/</guid><description>Learn how to set up your Rails application as an LTI Tool Provider, to handle LTI 1.3 launches from an LMS, including the OCID workflow, user authentication and what to do with the information you get from the LMS.</description><pubDate>Sun, 05 May 2024 13:26:00 GMT</pubDate></item><item><title>What&apos;s in a Canvas LMS LTI 1.3 JWT?</title><link>https://cbennell.com/posts/whats-in-a-canvas-lms-lti-1-3-jwt/</link><guid isPermaLink="true">https://cbennell.com/posts/whats-in-a-canvas-lms-lti-1-3-jwt/</guid><description>What’s inside an LTI 1.3 JWT? This post walks through a Canvas launch token claim by claim, so you can decode and understand the data your Rails app receives.</description><pubDate>Sat, 04 May 2024 04:00:00 GMT</pubDate></item><item><title>Parameterized Modules in Ruby</title><link>https://cbennell.com/posts/parameterized-modules-in-ruby/</link><guid isPermaLink="true">https://cbennell.com/posts/parameterized-modules-in-ruby/</guid><description>Ruby lets you use `[]` for more than arrays—and that opens the door to clever tricks like parameterized modules.</description><pubDate>Wed, 01 May 2024 04:31:00 GMT</pubDate></item><item><title>On &quot;Layered Design for Ruby on Rails Applications&quot;</title><link>https://cbennell.com/posts/on-layered-design-for-ruby-on-rails-applications/</link><guid isPermaLink="true">https://cbennell.com/posts/on-layered-design-for-ruby-on-rails-applications/</guid><description>From DDD-inspired architecture to patterns like query objects and service layers, Dementyev’s book explores how Rails apps can evolve stronger abstractions over time. Ideal for developers who want to move beyond basics and design with clarity and intent.</description><pubDate>Sun, 28 Apr 2024 02:11:00 GMT</pubDate></item></channel></rss>