<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>larsp.de</title><description>Digital garden about web development, Ruby on Rails, telephony, and tools Lars finds useful.</description><link>https://larsp.de/</link><language>en-US</language><atom:link href="https://larsp.de/rss.xml" rel="self" type="application/rss+xml"/><item><title>AI/LLM Resources</title><link>https://larsp.de/posts/ai-llm-resources/</link><guid isPermaLink="true">https://larsp.de/posts/ai-llm-resources/</guid><description>A curated collection of artificial intelligence and large language model resources, including Claude Code tools, plugins, MCP servers, spec-driven workflows and Ruby/Rails AI frameworks.</description><pubDate>Sun, 19 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Collection of Artificial Intelligence / LLM resources I actually use day to day. Biased towards Claude and the Ruby ecosystem, because that&apos;s where I spend most of my time.&lt;/p&gt;
&lt;h2&gt;Claude Code&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.anthropic.com/claude-code?ref=larsp.de&quot;&gt;Claude Code&lt;/a&gt; is Anthropic&apos;s agentic coding CLI. It lives in the terminal, reads and edits files, runs commands, and keeps track of project context across sessions. Paired with &lt;code&gt;CLAUDE.md&lt;/code&gt; files in the repo root, it becomes a pretty capable pair programmer.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/cli-reference?ref=larsp.de&quot;&gt;CLI reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kadekillary.work/blog/?ref=larsp.de#2025-06-16-snorting-the-agi-with-claude-code&quot;&gt;Interesting uses, e.g. let Claude generate a presentation of your codebase with Marp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://benenewton.com/blog/claude-code-roadmap-management?ref=larsp.de&quot;&gt;Roadmap management with Claude Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Plugins &amp;amp; extensions&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/anthropics/claude-code/tree/main/plugins/ralph-wiggum?ref=larsp.de&quot;&gt;Ralph Wiggum plugin&lt;/a&gt; — a Stop-hook that catches Claude trying to exit and feeds the same prompt back in. Useful for iterative tasks with clear success criteria (&quot;all tests green&quot;) where you want the agent to keep grinding until it&apos;s done.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openai/codex-plugin-cc?ref=larsp.de&quot;&gt;Codex plugin for Claude Code&lt;/a&gt; — makes OpenAI&apos;s Codex available from inside Claude Code. Handy for a second opinion (&lt;code&gt;/codex:review&lt;/code&gt;, &lt;code&gt;/codex:adversarial-review&lt;/code&gt;) or for delegating background tasks (&lt;code&gt;/codex:rescue&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Spec-driven workflows&lt;/h3&gt;
&lt;p&gt;Both of these treat specifications as the source of truth: you write the spec first, then agents implement against it. Different flavours for different project sizes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/automazeio/ccpm?ref=larsp.de&quot;&gt;CCPM – Claude Code Project Management&lt;/a&gt; — uses GitHub Issues and Git worktrees to let up to 12 Claude instances work in parallel. Workflow is Brainstorm → PRD → Epic → Issues → Tracking, all via &lt;code&gt;/pm:*&lt;/code&gt; slash commands.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Priivacy-ai/spec-kitty?ref=larsp.de&quot;&gt;Spec Kitty&lt;/a&gt; — CLI plus live Kanban dashboard, 6-phase lifecycle (spec → plan → tasks → implement → review → merge). Supports 12 agents including Claude Code, Cursor, Windsurf, Gemini and GitHub Copilot.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Agent Skills&lt;/h2&gt;
&lt;p&gt;Skills are self-contained capability packages — a folder of instructions, scripts and resources that Claude can load on demand.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.claude.com/en/docs/agents-and-tools/agent-skills/overview?ref=larsp.de&quot;&gt;Agent Skills – official docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/anthropics/claude-cookbooks/tree/main/skills?ref=larsp.de&quot;&gt;Claude Cookbooks: Skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/anthropics/skills?ref=larsp.de&quot;&gt;Public skills repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Model Context Protocol (MCP)&lt;/h2&gt;
&lt;p&gt;MCP is the open protocol that lets LLMs talk to external tools and data sources in a standardised way. The magic is that any MCP-compatible client (Claude Desktop, Claude Code, Cursor, …) can use any MCP server.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://modelcontextprotocol.io/introduction?ref=larsp.de&quot;&gt;Get started with the Model Context Protocol&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MCP servers I rely on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://linear.app/integrations/claude?ref=larsp.de&quot;&gt;Linear MCP&lt;/a&gt; — read and update Linear issues from within Claude.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/robertn702/mcp-sunsama?ref=larsp.de&quot;&gt;Sunsama MCP&lt;/a&gt; — full CRUD on Sunsama tasks, subtasks and streams. Great for keeping the daily plan in sync without leaving the terminal.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/M-Pineapple/member-berries-apple-mcp?ref=larsp.de&quot;&gt;Member Berries MCP&lt;/a&gt; — built on apple-mcp, adds memory-style tools for calendar, notes and reminders. Turns Claude into &quot;a helpful friend who remembers your day&quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Ruby/Rails tools and frameworks&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CultivateLabs/raif?ref=larsp.de&quot;&gt;Raif (Ruby AI Framework)&lt;/a&gt; — a Rails engine that helps you add AI-powered features to your Rails apps.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/obie/claude-on-rails?ref=larsp.de&quot;&gt;Claude on Rails&lt;/a&gt; — Obie Fernandez&apos;s framework that orchestrates specialised agents (Architect, Models, Controllers, Views, Services, Tests, DevOps) on top of &lt;code&gt;claude-swarm&lt;/code&gt;. Rails-aware, test-driven, integrates with the Rails MCP Server for up-to-date documentation.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jekyll/classifier-reborn?ref=larsp.de&quot;&gt;classifier-reborn&lt;/a&gt; — a general classifier module for Bayesian and other types of classification. Pre-LLM, but still useful for lightweight text categorisation without calling an API.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Resources</category><category>AI</category></item><item><title>IMAP migration and backup</title><link>https://larsp.de/posts/imap-migration-and-backup/</link><guid isPermaLink="true">https://larsp.de/posts/imap-migration-and-backup/</guid><description>Notes on moving mail between servers and keeping local backups. The article covers two primary tools: imapsync for server-to-server migration and imap-backup for offline archiving.</description><pubDate>Thu, 05 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Tools for working with IMAP accounts.&lt;/p&gt;
&lt;p&gt;Notes on moving mail between servers and keeping local backups.&lt;/p&gt;
&lt;h2&gt;imapsync&lt;/h2&gt;
&lt;p&gt;The go-to tool. Handles folder mapping, deduplication, resumable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;imapsync \
  --host1 old.server.com --user1 me@old.com --password1 xxx \
  --host2 new.server.com --user2 me@new.com --password2 yyy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Flags I actually use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--dry                     # test run
--exclude &quot;Spam|Trash&quot;    # skip junk
--folder &quot;INBOX&quot;          # single folder only
--regextrans2 s/Sent Items/Sent/  # rename folders
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://imapsync.lamiral.info/?ref=larsp.de&quot;&gt;imapsync.lamiral.info&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;imap-backup&lt;/h2&gt;
&lt;p&gt;Ruby gem, stores mail as Mbox + JSON index. Good for offline archives.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem install imap-backup
imap-backup setup    # interactive config
imap-backup backup   # run it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/joeyates/imap-backup?ref=larsp.de&quot;&gt;github.com/joeyates/imap-backup&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Gotchas&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Gmail/iCloud need app passwords&lt;/li&gt;
&lt;li&gt;Check destination quota before migrating&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--dry&lt;/code&gt; first, always&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Tools</category></item><item><title>Open Source Software</title><link>https://larsp.de/posts/open-source-software/</link><guid isPermaLink="true">https://larsp.de/posts/open-source-software/</guid><description>A curated collection of excellent open source web applications organized by category, including tools for chat, content management, development, document handling, home automation, hosting, email, project management, and task tracking.</description><pubDate>Wed, 21 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recommendable (web) applications&lt;/p&gt;
&lt;h2&gt;Chat / Messaging&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/basecamp/once-campfire&quot;&gt;once-campfire&lt;/a&gt;&lt;/strong&gt; - GitHub repository by Basecamp&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://revolt.chat/&quot;&gt;Revolt&lt;/a&gt;&lt;/strong&gt; - A chat application designed with community in mind&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://gotify.net/&quot;&gt;Gotify&lt;/a&gt;&lt;/strong&gt; - A simple server for sending and receiving messages&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;CMS&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://larsp.de/ghost-cms/&quot;&gt;Ghost CMS&lt;/a&gt;&lt;/strong&gt; - An open-source CMS favored for content sites&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://once.com/writebook&quot;&gt;Writebook&lt;/a&gt;&lt;/strong&gt; - Publish your own books on the web for free&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Development&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/TestLinkOpenSourceTRMS/testlink-code&quot;&gt;TestLink&lt;/a&gt;&lt;/strong&gt; - Open source test and requirement management system&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Document Management&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/paperless-ngx/paperless-ngx&quot;&gt;paperless-ngx&lt;/a&gt;&lt;/strong&gt; - A document management system for scanning, indexing, and archiving documents&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Home&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.home-assistant.io/&quot;&gt;Home Assistant&lt;/a&gt;&lt;/strong&gt; - Open source home automation with local control and privacy first, ideal for Raspberry Pi or local servers&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Hosting&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://databasus.com/&quot;&gt;Databasus&lt;/a&gt;&lt;/strong&gt; - Free tool for PostgreSQL scheduled backups with cloud storage and notifications&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://larsp.de/dokku-open-source-heroku-alternative/&quot;&gt;Dokku&lt;/a&gt;&lt;/strong&gt; - Self-hosted open-source PaaS alternative to Heroku&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/9001/copyparty&quot;&gt;copyparty&lt;/a&gt;&lt;/strong&gt; - Portable file server with WebDAV, FTP, TFTP, and media indexing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Mail&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.useplunk.com/&quot;&gt;Plunk&lt;/a&gt;&lt;/strong&gt; - Open-source email platform combining marketing, transactional, and broadcast emails&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Project Management&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.openproject.org/&quot;&gt;OpenProject&lt;/a&gt;&lt;/strong&gt; - Open source project management with task management, Gantt charts, boards, and team collaboration&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Tasks&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://tasktrove.io/&quot;&gt;TaskTrove&lt;/a&gt;&lt;/strong&gt; - Self-hostable, privacy-focused TODO list management application&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Software</category></item><item><title>Ruby on Rails resources</title><link>https://larsp.de/posts/ruby-on-rails-resources/</link><guid isPermaLink="true">https://larsp.de/posts/ruby-on-rails-resources/</guid><description>A comprehensive link directory and continually updated notes for Ruby on Rails development, covering admin interfaces, APIs, authentication, caching, databases, testing, and more.</description><pubDate>Wed, 21 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Link directory and notes for Ruby on Rails. Continually updated.&lt;/p&gt;
&lt;p&gt;My link directory and notes for Ruby on Rails. As usual, a work in progress and continually updated.&lt;/p&gt;
&lt;h3&gt;Admin interfaces&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/excid3/madmin?ref=larsp.de&quot;&gt;Madmin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://avohq.io/?ref=larsp.de&quot;&gt;Avo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;AI&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CultivateLabs/raif?ref=larsp.de&quot;&gt;Raif (Ruby AI Framework)&lt;/a&gt; is a Rails engine that helps you add AI-powered features to your Rails apps&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;APIs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Apipie/apipie-rails?ref=larsp.de&quot;&gt;Apipie&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gregschmit/rails-rest-framework?ref=larsp.de&quot;&gt;A framework for DRY RESTful APIs in Ruby on Rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.educative.io/courses/building-api-rails?ref=larsp.de&quot;&gt;Building your own API with Rails - Learn Interactively&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zuplo.com/blog/2025/04/13/ruby-rage-rest-api-tutorial?ref=larsp.de&quot;&gt;Building High Performance Ruby REST APIs with Rage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Apple Wallet&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://avohq.io/blog/apple-wallet-passes-in-rails-apps?ref=larsp.de&quot;&gt;Apple Wallet Passes in Rails Apps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Authorization&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://avohq.io/blog/rails-api-authentication-with-the-auth-generator?ref=larsp.de&quot;&gt;Rails API Authentication with the auth generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://avohq.io/blog/sign-in-with-apple-rails?ref=larsp.de&quot;&gt;Sign in with Apple for Rails apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://avohq.io/blog/passwordless-authentication-rails-no-password?ref=larsp.de&quot;&gt;Passwordless authentication with the NoPassword gem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.appsignal.com/2024/07/17/an-introduction-to-auth0-for-ruby-on-rails.html?ref=larsp.de&quot;&gt;An Introduction to Auth0 for Ruby on Rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/enjaku4/rabarber?ref=larsp.de&quot;&gt;GitHub - enjaku4/rabarber: Simple authorization library for Ruby on Rails&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;rails g sessions
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Bundling&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://propshaft-rails.com/?ref=larsp.de&quot;&gt;Propshaft&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Caching&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.appsignal.com/2024/08/14/an-introduction-to-http-caching-in-ruby-on-rails.html?ref=larsp.de&quot;&gt;An Introduction to HTTP Caching in Ruby On Rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.prateekcodes.dev/rails-http-caching-strategies/?ref=larsp.de&quot;&gt;HTTP Caching for Rails APIs: The Missing Performance Layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rails/solid_cache?ref=larsp.de&quot;&gt;rails/solid_cache: A database-backed ActiveSupport::Cache::Store&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Memcache&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://signalvnoise.com/posts/3113-how-key-based-cache-expiration-works?ref=larsp.de&quot;&gt;How key-based cache expiration works – Signal v. Noise&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;def get_ops client_id
  latest_import = ImportLog.maximum :updated_at
  cache_tag = &quot;ops-#{client_id}-#{latest_import.iso8601}&quot;
  Rails.cache.fetch(cache_tag, expires_in: 1.day) do
    Rails.logger.info(&quot;Cache miss for #{cache_tag}&quot;)
    Op.where(client_id: client_id).to_json
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;CAPTCHAs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ambethia/recaptcha?ref=larsp.de&quot;&gt;https://github.com/ambethia/recaptcha&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CLI&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gurgeous/table_tennis?ref=larsp.de&quot;&gt;TableTennis&lt;/a&gt; is a Ruby library for printing stylish tables in your terminal&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CMS&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/AlchemyCMS?ref=larsp.de&quot;&gt;AlchemyCMS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sitepress.cc/?ref=larsp.de&quot;&gt;Sitepress&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Concurrency&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Subprocess
pid = Process.fork do 
  long_process
end
Process.detach pid
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Config&lt;/h3&gt;
&lt;p&gt;ActiveSupport::Configurable&lt;/p&gt;
&lt;h3&gt;Commerce&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://businessclasskit.com/?ref=larsp.de&quot;&gt;https://businessclasskit.com&lt;/a&gt; (SaaS with Gumroad integration)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CSS&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com/docs/installation/framework-guides/ruby-on-rails?ref=larsp.de&quot;&gt;Install Tailwind CSS with Ruby on Rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flowbite.com/docs/getting-started/rails/?ref=larsp.de&quot;&gt;https://flowbite.com/docs/getting-started/rails/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Databases&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://testdouble.com/insights/using-cockroachdb-with-rails?ref=larsp.de&quot;&gt;CockroachDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rails-sqlserver/activerecord-sqlserver-adapter?ref=larsp.de&quot;&gt;activerecord-sqlserver-adapter: SQL Server Adapter For Rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thbar/kiba?ref=larsp.de&quot;&gt;kiba - Data processing &amp;amp; ETL framework for Ruby&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Indices&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Exclude nulls from indexes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A database index is a B-tree structure. It is very efficient when data has a high cardinality. However, when a column allows nulls, it often becomes the most redundant value. The index is less efficient and takes up more space. Unless null is an infrequently repeated value, there are only disadvantages to indexing them.&lt;/p&gt;
&lt;p&gt;Exclude them when creating the index with a where clause.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add_index :table, :column, where: &quot;(column IS NOT NULL)&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or in pure SQL:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE INDEX name ON table (column) \
  WHERE column IS NOT NULL;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Do not index column with a low cardinality such as boolean&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The reason is the same as in the previous paragraph. B-tree indexes work best when cardinality is high. So a Boolean is the worst column you can index. So don&apos;t index booleans.&lt;/p&gt;
&lt;p&gt;As with other types, if you have very repetitive values that are not significant from a business point of view, it&apos;s probably a good idea to exclude.&lt;/p&gt;
&lt;h3&gt;Debugging&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/charkost/prosopite?ref=larsp.de&quot;&gt;Prosopite&lt;/a&gt; is able to auto-detect Rails N+1 queries&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Development&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/voormedia/rails-erd?ref=larsp.de&quot;&gt;rails-erd: Generate Entity-Relationship Diagrams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Duartemartins/rails_copilot_instructions?ref=larsp.de&quot;&gt;Rails 8 Copilot Instructions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/de/actions/use-cases-and-examples/building-and-testing/building-and-testing-ruby?ref=larsp.de&quot;&gt;GitHub Actions for Ruby projects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lape/devcontainer-rails?ref=larsp.de&quot;&gt;https://github.com/lape/devcontainer-rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/github/scientist?ref=larsp.de&quot;&gt;github/scientist: A Ruby library for carefully refactoring critical paths.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Documentation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nshki/chusaku?ref=larsp.de&quot;&gt;nshki/chusaku: Annotate your Rails controllers with route info.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Error Reporting and Exception Handling&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fractaledmind/solid_errors?ref=larsp.de&quot;&gt;Solid Errors&lt;/a&gt; is a DB-based, app-internal exception tracker for Rails applications, designed with simplicity and performance in mind.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Events&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://railseventstore.org/?ref=larsp.de&quot;&gt;Rails Event Store&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Files and Storage&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# tempfiles
Tempfile.open(&quot;voucher&quot;, Rails.root.join(&quot;tmp&quot;)) do |f|
  f.print(price.name)
  f.flush
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Forms&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/heartcombo/simple_form?ref=larsp.de&quot;&gt;https://github.com/heartcombo/simple_form&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://avohq.io/blog/multistep-forms-rails?ref=larsp.de&quot;&gt;Multistep forms with Rails and the Wicked gem&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Date Picker&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;%= f.text_field :birthday, label: t(:form_birthday),
    floating: true, required: true,
    data: {
      controller: &quot;flatpickr&quot;,
      flatpickr_date_format: &quot;d.m.Y&quot;,
      flatpickr_min_date: &quot;1900-01-01&quot;,
      flatpickr_allow_input: true,
    }
%&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Frontend&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://viewcomponent.org/?ref=larsp.de&quot;&gt;ViewComponent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://avohq.io/blog/breadcrumbs-rails?ref=larsp.de&quot;&gt;Breadcrumbs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://railsblocks.com/?ref=larsp.de&quot;&gt;Rails Blocks&lt;/a&gt; UI components&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/leonvogt/hotwire-dev-tools?ref=larsp.de&quot;&gt;Hotwire dev tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rubyui.com/?ref=larsp.de&quot;&gt;RubyUI&lt;/a&gt; component library&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.betterstimulus.com/?ref=larsp.de&quot;&gt;Better StimulusJS Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marmelab.com/blog/2025/04/18/give-a-spa-feel-to-your-static-website-with-turbo.html?ref=larsp.de&quot;&gt;Give a SPA Feel to Your Static Website with Hotwire&apos;s Turbo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.phlex.fun/?ref=larsp.de&quot;&gt;Phlex&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Gems&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ruby-toolbox.com/?ref=larsp.de&quot;&gt;Ruby Toolbox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Generators&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;rails g scaffold_controller
rails g migration addAddressToOps address:reference
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Hosting&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://larsp.de/dokku-open-source-heroku-alternative/&quot;&gt;Dokku&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Howtos/Guides&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hopsoft/rails_standards?ref=larsp.de&quot;&gt;https://github.com/hopsoft/rails_standards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/krschacht/37signals-rails-code?ref=larsp.de&quot;&gt;Well-written code examples by 37signals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://railsinspire.com/?ref=larsp.de&quot;&gt;https://railsinspire.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://boringrails.com/?ref=larsp.de&quot;&gt;Boring Rails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ankane/production_rails?ref=larsp.de&quot;&gt;ankane/production_rails: Best practices for running Rails in production&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/eliotsykes/real-world-rails?ref=larsp.de&quot;&gt;eliotsykes/real-world-rails: Real World Rails applications and their open source codebases for developers to learn from&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Images&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fileboost.dev/?ref=larsp.de&quot;&gt;Fileboost&lt;/a&gt; - Supercharge Your Rails Images&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Jobs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://mileswoodroffe.com/articles/solid-queue-and-mission-control?ref=larsp.de&quot;&gt;https://mileswoodroffe.com/articles/solid-queue-and-mission-control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.37signals.com/introducing-solid-queue?ref=larsp.de&quot;&gt;https://dev.37signals.com/introducing-solid-queue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rails/mission_control-jobs?ref=larsp.de&quot;&gt;https://github.com/rails/mission_control-jobs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.driftingruby.com/episodes/processing-large-jobs?ref=larsp.de&quot;&gt;https://www.driftingruby.com/episodes/processing-large-jobs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;SOLID_QUEUE_IN_PUMA=1&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/radioactive-labs/chrono_forge?ref=larsp.de&quot;&gt;chrono_forge&lt;/a&gt; - a robust framework for building durable, distributed workflows in Ruby on Rails applications&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Logging&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/images/posts/ruby-on-rails-resources/logbench-preview.png&quot; alt=&quot;log_bench terminal UI preview&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;log_bench&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/silva96/log_bench?ref=larsp.de&quot;&gt;log_bench&lt;/a&gt; - A terminal-based Rails log viewer with real-time monitoring and filtering capabilities&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://railsnotes.xyz/blog/ahoy-product-analytics?ref=larsp.de&quot;&gt;Internal product analytics with Ahoy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Honeybadger&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;Honeybadger.event(&quot;SUCCESS&quot;, 
  { message: &quot;A new customer just signed up&quot; })
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Mail&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/joshmn/caffeinate?ref=larsp.de&quot;&gt;joshmn/caffeinate: A Rails engine for drip campaigns/scheduled sequences and periodical support. Works with ActionMailer, and other things.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Migration&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.akshaykhot.com/rails-database-migrations-cheatsheet/?ref=larsp.de&quot;&gt;https://www.akshaykhot.com/rails-database-migrations-cheatsheet/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Load schema instead of migrations&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake db:schema:load
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&apos;re on the latest (8) version of Ruby on Rails, there&apos;s a nice shortcut to add the not null modifier to your database columns. Just add an exclamation mark after the type, and Rails will mark that column as not null.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rails generate migration CreateUsers \
  email_address:string!:uniq password_digest:string!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;MySQL&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ALTER USER &apos;opos&apos;@&apos;localhost&apos; \
  IDENTIFIED WITH mysql_native_password BY &apos;opos&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://guides.rubyonrails.org/active_record_multiple_databases.html?ref=larsp.de&quot;&gt;Multiple Databases with Active Record — Ruby on Rails Guides&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# models/application_record.rb     
class ApplicationRecord &amp;lt; ActiveRecord::Base
  primary_abstract_class
  connects_to database: {writing: :primary, reading: :primary_replica}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Payment&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/activemerchant/active_merchant?ref=larsp.de&quot;&gt;Active Merchant&lt;/a&gt; is a simple payment abstraction library extracted from Shopify&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pay-rails/pay?ref=larsp.de&quot;&gt;Pay gem&lt;/a&gt; - used in &lt;a href=&quot;https://jumpstartrails.com/?ref=larsp.de&quot;&gt;Jumpstart Pro&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;PDF&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/prawnpdf/prawn?ref=larsp.de&quot;&gt;https://github.com/prawnpdf/prawn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://larsp.de/barcode-pdfs-with-ruby-on-rails/&quot;&gt;Barcode PDFs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;PostgreSQL&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pawurb/rails-pg-extras?ref=larsp.de&quot;&gt;https://github.com/pawurb/rails-pg-extras&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Proxy&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.37signals.com/thruster-released/?ref=larsp.de&quot;&gt;37signals Dev — Thruster HTTP/2&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Redis&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/50985766/how-to-use-redis-with-rails?ref=larsp.de&quot;&gt;How to use Redis with Rails? - Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Rich Text&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://dante-editor.dev/?ref=larsp.de&quot;&gt;https://dante-editor.dev&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Routing&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://books.writesoftwarewell.com/3/rails-router?ref=larsp.de&quot;&gt;Rails Router Handbook&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Search&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://avohq.io/blog/intelligent-search-in-rails-with-typesense?ref=larsp.de&quot;&gt;Typesense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jetthoughts.com/blog/art-of-form-objects-elegant-search/?ref=larsp.de&quot;&gt;The Art of Form Objects: Elegant Search Filtering in Rails&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Security&lt;/h3&gt;
&lt;h4&gt;Rate limiting&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://mileswoodroffe.com/articles/rails-rate-limiting?ref=larsp.de&quot;&gt;Rate Limiting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.prateekcodes.dev/rails-8-multiple-rate-limits-per-controller/?ref=larsp.de&quot;&gt;Rails 8 adds ability to use multiple rate limits per controller&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Scraping&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/glaucocustodio/tanakai?ref=larsp.de&quot;&gt;https://github.com/glaucocustodio/tanakai&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Storage&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://edgeguides.rubyonrails.org/active_storage_overview.html?ref=larsp.de&quot;&gt;Active Storage Overview — Ruby on Rails Guides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pragmaticstudio.com/tutorials/using-active-storage-in-rails?ref=larsp.de&quot;&gt;Using Active Storage in Rails 7&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;# Purge orphan files and blob records
ActiveStorage::Blob.unattached.each(&amp;amp;:purge)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;SQLite&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fractaledmind/litestream-ruby?ref=larsp.de&quot;&gt;https://github.com/fractaledmind/litestream-ruby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Must have (according to &lt;a href=&quot;https://youtu.be/3GfLdP3E1bo?ref=larsp.de&quot;&gt;Stephen Margheim at RailsConf 2024&lt;/a&gt;): &lt;a href=&quot;https://github.com/fractaledmind/activerecord-enhancedsqlite3-adapter?ref=larsp.de&quot;&gt;https://github.com/fractaledmind/activerecord-enhancedsqlite3-adapter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fractaledmind/litestream-ruby?ref=larsp.de&quot;&gt;https://github.com/fractaledmind/litestream-ruby&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Testing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thoughtbot/climate_control?ref=larsp.de&quot;&gt;Environment variables with climate_control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://buttondown.com/kaspth/archive/why-is-oaken-for-your-database-seeds-test-data/?ref=larsp.de&quot;&gt;https://buttondown.com/kaspth/archive/why-is-oaken-for-your-database-seeds-test-data/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.shakacode.com/blog/exploring-the-ffaker-gem/?ref=larsp.de&quot;&gt;Exploring the FFaker Gem - A Comprehensive Guide | Shakacode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Minitest&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://minitest.rubystyle.guide/?ref=larsp.de&quot;&gt;Minitest Style Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rubypigeon.com/posts/minitest-cheat-sheet/?ref=larsp.de&quot;&gt;Minitest Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;# test_helper.rb
# Set up minitest-reporters to show a 
# spec-style progress report.
require &quot;minitest/reporters&quot;
Minitest::Reporters.use! 
  [Minitest::Reporters::SpecReporter.new]
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Capybara System Tests&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;bin/rails generate system_test users
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Test Coverage&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;# test_helper.rb
require &quot;simplecov&quot;
SimpleCov.start &quot;rails&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Templates/ERB&lt;/h3&gt;
&lt;h4&gt;Disable Turbo&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;%= link_to l.to_s.upcase, &quot;/#{l}&quot;, 
  class: (&quot;active&quot; if locale == l), 
  data: {&quot;turbo&quot;: false } %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Translation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://larsp.de/rails-translation-cheatsheet/&quot;&gt;Rails translation cheatsheet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Updating&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://davidrunger.com/blog/using-vs-code-as-a-rails-app-update-merge-tool?ref=larsp.de&quot;&gt;Using VS Code as a Rails app:update merge tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://discuss.rubyonrails.org/t/rails-migrating-from-sprockets-to-propshaft/87992?ref=larsp.de&quot;&gt;Rails - Migrating from Sprockets to Propshaft&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rubyonrails.org/2024/11/7/rails-8-no-paas-required?ref=larsp.de&quot;&gt;https://rubyonrails.org/2024/11/7/rails-8-no-paas-required&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gorails.com/series/whats-new-in-rails-8?ref=larsp.de&quot;&gt;https://gorails.com/series/whats-new-in-rails-8&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;URLs&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://avohq.io/blog/canonical-urls-rails?ref=larsp.de&quot;&gt;Canonical URLs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Ruby on Rails</category><category>Resources</category></item><item><title>Favorite CLI Tools</title><link>https://larsp.de/posts/favorite-cli-tools/</link><guid isPermaLink="true">https://larsp.de/posts/favorite-cli-tools/</guid><description>Command line tool recommendations that save time and improve developer workflows. A curated collection of CLI tools including bat, HTTPie, jq, and others that I find essential for daily work.</description><pubDate>Wed, 12 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Command line tool recommendations&lt;/p&gt;
&lt;p&gt;These CLI tools save me lots of time and I find them generally a joy to work with. It&apos;s all about sharing the love and magic, and maybe you&apos;ll find a new favorite or two. Let me &lt;a href=&quot;https://larsp.de/contact/&quot;&gt;know&lt;/a&gt; if you have a CLI tool that brings you joy - or comment below.&lt;/p&gt;
&lt;h2&gt;bat - a cat(1) clone with wings&lt;/h2&gt;
&lt;p&gt;I love this. It&apos;s a drop-in replacement for &lt;code&gt;cat&lt;/code&gt; that adds syntax highlighting, Git integration and lots more. It&apos;s written in Rust and is blazing fast. &lt;a href=&quot;https://github.com/sharkdp/bat?ref=larsp.de&quot;&gt;sharkdp/bat: A cat(1) clone with wings&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;How to use bat&lt;/h3&gt;
&lt;p&gt;To glance at a file using &lt;code&gt;bat&lt;/code&gt;, simply provide the path:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bat /path/to/your/file
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The syntax highlighting and file-specific metadata make &lt;code&gt;bat&lt;/code&gt; a joy to use, ensuring you can inspect code and text files in style.&lt;/p&gt;
&lt;h2&gt;Claude Code&lt;/h2&gt;
&lt;p&gt;Even though it&apos;s more application than classic tool, my favorite command line tool has recently become &lt;a href=&quot;https://docs.anthropic.com/en/docs/claude-code/overview?ref=larsp.de&quot;&gt;Claude Code&lt;/a&gt; (also see &lt;a href=&quot;https://larsp.de/ai-llm-resources/&quot;&gt;AI/LLM index page&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Homebrew - The missing macOS package manager&lt;/h2&gt;
&lt;p&gt;It&apos;s simply a must-have for every Mac user. Whether it&apos;s installing a new programming language, a database server, or the latest web framework, Homebrew streamlines the process, taking out the need for locating and manually downloading software.&lt;/p&gt;
&lt;h3&gt;The brew command&lt;/h3&gt;
&lt;p&gt;Working with Homebrew is straightforward:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew update
brew install &amp;lt;package&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;httpie - HTTP client for the command line&lt;/h2&gt;
&lt;p&gt;Making HTTP requests from the command line has never been more elegant than with httpie. It simplifies interaction with APIs and web services, offering a user-friendly interface and an eye-pleasing HTTP request syntax colorization.&lt;/p&gt;
&lt;p&gt;There also is a very neat &lt;a href=&quot;https://httpie.io/desktop?ref=larsp.de&quot;&gt;httpie desktop application&lt;/a&gt;!&lt;/p&gt;
&lt;h3&gt;Crafting requests with httpie&lt;/h3&gt;
&lt;p&gt;A basic GET request:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https httpie.io/hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &quot;ahoy&quot;: [
        &quot;Hello, World! 👋 Thank you for trying out HTTPie 🥳&quot;,
        &quot;We hope this will become a friendship.&quot;
    ],
    &quot;links&quot;: {
        &quot;discord&quot;: &quot;https://httpie.io/discord&quot;,
        &quot;github&quot;: &quot;https://github.com/httpie&quot;,
        &quot;homepage&quot;: &quot;https://httpie.io&quot;,
        &quot;twitter&quot;: &quot;https://twitter.com/httpie&quot;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;jq - Command-line JSON processor&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;jq&lt;/code&gt; is a sed-like tool that parses, manipulates, and displays JSON objects from the comfort of the command line. It excels at selectively filtering and transforming complex JSON data, which is a common task when working with APIs and backend services.&lt;/p&gt;
&lt;h3&gt;Transforming with jq&lt;/h3&gt;
&lt;p&gt;Filtering results:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https httpie.io/hello | jq &quot;{links}&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will present just the links from the JSON response. &lt;code&gt;jq&lt;/code&gt; is nice for quickly juggling JSON data.&lt;/p&gt;
&lt;h2&gt;kopia - Fast and Secure Open-Source Backup Software&lt;/h2&gt;
&lt;p&gt;Encrypted backups with &lt;a href=&quot;https://kopia.io/?ref=larsp.de&quot;&gt;kopia&lt;/a&gt; to Amazon S3 and any cloud storage that is compatible with S3, Azure Blob Storage, Backblaze B2, Google Cloud Storage, WebDAV, SFTP, Rclone.&lt;/p&gt;
&lt;h3&gt;Creating a repository (e.g. SFTP)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kopia repository create sftp \
      --path=... \
      --host=... \
      --username=... \
      --sftp-password=...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Connecting to a repository&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kopia repository connect sftp \
      --path=... \
      --host=... \
      --username=...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Creating a snapshot&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;kopia snapshot create $HOME/Projects/github.com/kopia/kopia
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;lando - Local development environment and DevOps tool built on Docker containers&lt;/h2&gt;
&lt;p&gt;For local development, &lt;a href=&quot;https://lando.dev/?ref=larsp.de&quot;&gt;lando&lt;/a&gt; is mighty. It configures and manages Docker-based development environments, providing an abstraction layer that spares developers the mundanity of configuring development Docker environments and installing necessary tools and software versions.&lt;/p&gt;
&lt;h3&gt;A lando starter&lt;/h3&gt;
&lt;p&gt;Creating a Wordpress site:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lando init --recipe wordpress
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with that simple command, you&apos;re on your way to local Wordpress development with a containerized environment. &lt;code&gt;lando&lt;/code&gt; integrates with other tools such as composer, npm, and gulp to streamline development workflows. It&apos;s an excellent tool for building, testing, and deploying applications locally. One of the most powerful features is the ability to define multiple environments in a single configuration file (e.g. local, staging, production) that can be easily switched between.&lt;/p&gt;
&lt;h2&gt;lazygit - Terminal UI Git Command Manager&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jesseduffield/lazygit?ref=larsp.de&quot;&gt;lazygit&lt;/a&gt; is a simple yet powerful terminal UI with Norton Commander vibes that transforms how you interact with Git, making complex operations accessible through intuitive keyboard shortcuts.&lt;/p&gt;
&lt;p&gt;It reduces context switching. Instead of running multiple commands and checking different windows, everything is visible in one organized interface. The tool even guides you through operations interactively - for example, it warns about divergence with upstream when pushing and lets you choose between force push or cancel.&lt;/p&gt;
&lt;h2&gt;mise-en-place - Polyglot tool version manager&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://mise.jdx.dev/?ref=larsp.de&quot;&gt;mise&lt;/a&gt; is a tool that manages installations of programming language runtimes and other tools for local development. For example, it can be used to manage multiple versions of Node.js, Python, Ruby, Go, etc. on the same machine.&lt;/p&gt;
&lt;h2&gt;ohmyzsh - Delightful framework for managing your zsh configuration&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://ohmyz.sh/?ref=larsp.de&quot;&gt;ohmyzsh&lt;/a&gt; transforms the already powerful &lt;code&gt;zsh&lt;/code&gt; into a feature-rich and stylish terminal environment. With themes, plugins, and an active community contributing enhancements, ohmyzsh makes the terminal experience more personal and productive.&lt;/p&gt;
&lt;p&gt;ohmyzsh also comes packed with a variety of plugins that add new features to &lt;code&gt;zsh&lt;/code&gt;, such as an auto-suggestion tool and syntax highlighting, making it even more powerful. These can be easily enabled or disabled through the &lt;code&gt;~/.zshrc&lt;/code&gt; file as well.&lt;/p&gt;
&lt;h2&gt;zsh-autosuggestions&lt;/h2&gt;
&lt;p&gt;Getting along well with ohmyzsh, this tool offers context-aware auto-completion, predicting your command line moves, and saving keystrokes in the process. Start by typing a command and, based on your history, zsh-autosuggestions will begin offering predictions. You can cycle through suggestions with the right arrow key or accept one with the tab key.&lt;/p&gt;
&lt;h2&gt;rbenv - Ruby Version Manager&lt;/h2&gt;
&lt;p&gt;For managing multiple Ruby environments, &lt;a href=&quot;https://rbenv.org/?ref=larsp.de&quot;&gt;rbenv&lt;/a&gt; is vital. It allows for per-project Ruby versions, which is a blessing when working on legacy software that demands older Ruby interpreters alongside the current releases.&lt;/p&gt;
&lt;h3&gt;Install a Ruby version&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# List installable versions
rbenv install -l

3.1.6
3.2.6
3.3.7
3.4.3
jruby-9.4.10.0
mruby-3.3.0
picoruby-3.0.0
truffleruby-24.1.1
truffleruby+graalvm-24.1.1

# Build and install version 3.4.3
rbenv install 3.4.3
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Switching global Ruby version&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;rbenv global 3.4.3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This indicates that generally Ruby 3.4.3 should be used, while local projects can specify a different version in their &lt;code&gt;.ruby-version&lt;/code&gt; file. When executing &lt;code&gt;bundle&lt;/code&gt; command, or any other code that requires a Ruby environment, rbenv will use the specified or else the global version.&lt;/p&gt;
</content:encoded><category>Tools</category><category>Resources</category></item><item><title>MacOS setup</title><link>https://larsp.de/posts/macos-setup/</link><guid isPermaLink="true">https://larsp.de/posts/macos-setup/</guid><description>Installation and configuration steps for setting up a new Mac computer, including Homebrew package management, shell improvements with Oh My Zsh and Powerlevel10k, and development tools.</description><pubDate>Sun, 19 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My installation steps for setting up a new Mac computer.&lt;/p&gt;
&lt;h2&gt;Essentials&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# Homebrew (https://brew.sh)
/bin/bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)&quot;

# bat - better cat
brew install bat

# ripgrep - recursively searches directories for a regex pattern
brew install ripgrep
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Better Shell&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# Oh my zsh
sh -c &quot;$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)&quot;

# Powerlevel10k theme
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k

# Change theme in .zshrc
ZSH_THEME=&quot;powerlevel10k/powerlevel10k&quot;

# Syntax highlighting and auto suggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting

# Activate the plugin in ~/.zshrc:
plugins=(git zsh-syntax-highlighting zsh-autosuggestions)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Development&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;brew install git-delta
brew install httpie
brew install rbenv
brew install php
brew install yarn
brew install sass
brew install jq
brew install gh
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Install Homebrew packages from list&lt;/h2&gt;
&lt;h3&gt;Making a list of installed software&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;brew leaves &amp;gt; brews.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, include installed casks in the same list:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew list --cask &amp;gt;&amp;gt; brews.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This appends the cask list to brews.txt, giving a complete list of all explicitly installed packages.&lt;/p&gt;
&lt;h3&gt;Reviewing package descriptions&lt;/h3&gt;
&lt;p&gt;It is helpful to verify all packages are still needed on a new computer. Review packages as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat brews.txt | xargs brew desc –eval-all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command provides a short description for each package in the list.&lt;/p&gt;
&lt;h3&gt;Reinstalling on a new machine&lt;/h3&gt;
&lt;p&gt;Transfer brews.txt to the new computer, install Homebrew, and run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xargs brew install &amp;lt; brews.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This installs all the packages listed in the file.&lt;/p&gt;
</content:encoded><category>Tools</category></item><item><title>Ghost CMS</title><link>https://larsp.de/posts/ghost-cms/</link><guid isPermaLink="true">https://larsp.de/posts/ghost-cms/</guid><description>Ghost is a fantastic open-source, headless Node.js CMS that serves as my preferred system for setting up content sites. It&apos;s fully open-source and powers blogs for major organizations like OpenAI and Mozilla.</description><pubDate>Thu, 04 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My favorite open-source CMS for content sites&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ghost.org/?ref=larsp.de&quot;&gt;Ghost&lt;/a&gt; is a fantastic open-source, headless Node.js CMS and my go-to system for setting up content sites (e.g. my German consulting business site &lt;a href=&quot;https://itpeters.com/?ref=larsp.de&quot;&gt;itpeters.com&lt;/a&gt; or my private travel logbook &lt;a href=&quot;https://reisepedia.de/?ref=larsp.de&quot;&gt;reisepedia.de&lt;/a&gt;). Essentially, it&apos;s a customizable platform for running blogs, magazines, or journals. It&apos;s fully &lt;a href=&quot;https://github.com/TryGhost/Ghost?ref=larsp.de&quot;&gt;open-source&lt;/a&gt; and runs blogs from OpenAI, DigitalOcean, Mozilla and many other big names.&lt;/p&gt;
&lt;p&gt;The Ghost Foundation is offering a hosted version of Ghost, so it&apos;s accessible for non-technical content creators. This is really great and should be used by all means, if you don&apos;t want to deal with the technical aspects of running a web server. For me, however, it comes natural to set up a Ghost instance on my own server with the &lt;a href=&quot;https://hub.docker.com/_/ghost/?ref=larsp.de&quot;&gt;offical Docker image&lt;/a&gt; and &lt;a href=&quot;https://larsp.de/dokku-open-source-heroku-alternative/&quot;&gt;Dokku&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are also a ton of themes for purchase (and for free!) on &lt;a href=&quot;https://ghost.org/themes/?ref=larsp.de&quot;&gt;Ghost&apos;s official website&lt;/a&gt;. I personally like the themes from &lt;a href=&quot;https://brightthemes.com/?ref=larsp.de&quot;&gt;Bright Themes&lt;/a&gt;, which are very well designed and easy to customize. They offer a lifetime license for all themes, which I think is a fantastic deal. This site uses the &lt;a href=&quot;https://brightthemes.com/themes/array?ref=larsp.de&quot;&gt;Array&lt;/a&gt; theme by Bright Themes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/posts/ghost-cms/ghost-admin.png&quot; alt=&quot;Ghost CMS admin dashboard&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Key features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Very fast and stable&lt;/li&gt;
&lt;li&gt;Open Source (MIT license)&lt;/li&gt;
&lt;li&gt;Paid subscription and membership support&lt;/li&gt;
&lt;li&gt;SEO and social media optimization&lt;/li&gt;
&lt;li&gt;Newsletter integration&lt;/li&gt;
&lt;li&gt;Native REST API in core&lt;/li&gt;
&lt;li&gt;Admin dashboard&lt;/li&gt;
&lt;li&gt;Hosted version available&lt;/li&gt;
&lt;li&gt;Self-hosting possible and well-documented&lt;/li&gt;
&lt;li&gt;Great themes available (paid and free)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ghost.org/tutorials/code-snippets-in-ghost/?ref=larsp.de&quot;&gt;A complete guide to code snippets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://brightthemes.com/blog/ghost-syntax-highlighting?ref=larsp.de&quot;&gt;How to Add Syntax Highlighting to Ghost&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://baty.net/posts/2024/11/adding-an-edit-link-to-ghost-posts/?ref=larsp.de&quot;&gt;Adding an Edit link to Ghost posts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Notes&lt;/h2&gt;
&lt;h3&gt;Sort posts on last updated&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;{{#get &quot;posts&quot; include=&quot;authors,tags&quot; order=&quot;updated_at desc&quot;
  limit=@config.posts_per_page}}
  {{&amp;gt; post-feed}}
{{/get}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;index.hbs&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{{!-- Date --}}
&amp;lt;time class=&quot;leading-none font-medium&quot; datetime=&quot;{{date updated_at format=&quot;YYYY-MM-DD&quot;}}&quot;&amp;gt;{{date updated_at}}&amp;lt;/time&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;post-card.hbs&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Code word wrap&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;code[class*=&quot;language-&quot;], 
pre[class*=&quot;language-&quot;] {
    white-space: pre-wrap;
    overflow-wrap: break-word;
    word-break: normal;
    overflow-x: auto;
}

/* Mobile responsive adjustments */
@media screen and (max-width: 768px) {
    code[class*=&quot;language-&quot;], 
    pre[class*=&quot;language-&quot;] {
        font-size: 0.85em;
        line-height: 1.3;
        -webkit-overflow-scrolling: touch;
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>CMS</category></item><item><title>Dokku: Open source Heroku alternative</title><link>https://larsp.de/posts/dokku-open-source-heroku-alternative/</link><guid isPermaLink="true">https://larsp.de/posts/dokku-open-source-heroku-alternative/</guid><description>Dokku is a self-hosted open-source Platform as a Service similar to Heroku. It&apos;s lightweight, stable, and supports both Buildpacks and Dockerfiles for application deployment.</description><pubDate>Mon, 16 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dokku is a self-hosted open-source PaaS similar to Heroku.&lt;/p&gt;
&lt;p&gt;My favorite hosting solution for several years. It&apos;s lightweight, open-source and really stable. There are two general modes of operation: Buildpacks (e.g. Herokuish) and Dockerfiles.&lt;/p&gt;
&lt;p&gt;On a freshly installed Linux machine, after installing Dokku you can push to Git repos on the server, and a container will be build and started for your app, with Nginx as a reverse proxy running in front of everything.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;h3&gt;Linux&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# download the installation script
wget -NP . https://dokku.com/bootstrap.sh

# run the installer
sudo DOKKU_TAG=v0.35.18 bash bootstrap.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Mac (Homebrew)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;brew install dokku/repo/dokku
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Plugins&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dokku/dokku-letsencrypt&quot;&gt;dokku-letsencrypt&lt;/a&gt; - Automatic Let&apos;s Encrypt TLS Certificate installation&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dokku/dokku-mariadb&quot;&gt;dokku-mariadb&lt;/a&gt; - MariaDB plugin&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dokku/dokku-postgres&quot;&gt;dokku-postgres&lt;/a&gt; - PostgreSQL plugin&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dokku/dokku-redirect&quot;&gt;dokku-redirect&lt;/a&gt; - Simple redirects for applications&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;General config settings&lt;/h2&gt;
&lt;h3&gt;Change deploy branch&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;dokku git:set deploy-branch main
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Timezone&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;dokku config:set TZ=Europe/Berlin
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Nginx settings&lt;/h2&gt;
&lt;h3&gt;Disable HSTS header&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;dokku nginx:set hsts false
dokku proxy:build-config
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Max upload size&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;dokku nginx:set sitename client-max-body-size 25m
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Rate limiting&lt;/h3&gt;
&lt;p&gt;See &lt;a href=&quot;https://www.joseferben.com/posts/rate-limiting-with-dokku&quot;&gt;Rate limiting with dokku&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Redirects&lt;/h2&gt;
&lt;p&gt;Redirect www to non-www using &lt;a href=&quot;https://github.com/dokku/dokku-redirect&quot;&gt;dokku-redirect&lt;/a&gt; plugin:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dokku redirect:set larsp www.larsp.de larsp.de
-----&amp;gt; Configuring redirect for www.larsp.de to larsp.de via HTTP 301...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Ruby on Rails&lt;/h2&gt;
&lt;h3&gt;Rails config&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;dokku config:set myrailsapp \
  SECRET_KEY_BASE=mysecret RAILS_ENV=production \
  RACK_ENV=production RAILS_LOG_TO_STDOUT=enabled \
  RAILS_SERVE_STATIC_FILES=enabled
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;PHP&lt;/h2&gt;
&lt;h3&gt;Troubleshooting buildpack error&lt;/h3&gt;
&lt;p&gt;In case there is a problem with the PHP buildpack:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/tmp/buildpacks/08_buildpack-php/bin/compile: line 236: /tmp/buildpacks/08_buildpack-php/support/build/_util/formulae-hash.sh: No such file or directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reset the PHP herokuish buildpack:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rm -rf /home/dokku/&amp;lt;app&amp;gt;/cache/*
dokku config:set &amp;lt;app&amp;gt; BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-php --no-restart
dokku ps:rebuild &amp;lt;app&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Links&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kot-behemoth/awesome-dokku&quot;&gt;awesome-dokku&lt;/a&gt; - A curated list of awesome Dokku resources and tools&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Hosting</category><category>Tools</category></item><item><title>Rails translation cheatsheet</title><link>https://larsp.de/posts/rails-translation-cheatsheet/</link><guid isPermaLink="true">https://larsp.de/posts/rails-translation-cheatsheet/</guid><description>A practical guide demonstrating how to translate a Rails application, covering locale configuration, URL routing, and field translation using the Traco gem.</description><pubDate>Thu, 08 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;How to translate a Rails application.&lt;/p&gt;
&lt;h2&gt;Locales&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# config/application.rb

config.i18n.available_locales = %i[de fr it]
config.i18n.default_locale = :de
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# app/controllers/application_controller.rb

class ApplicationController &amp;lt; ActionController::Base
  around_action :switch_locale

  def switch_locale(&amp;amp;)
    locale = params[:locale] || I18n.default_locale
    I18n.with_locale(locale, &amp;amp;)
  end

  def default_url_options
    { locale: I18n.locale }
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# config/routes.rb

scope &quot;(:locale)&quot;, locale: /de|fr|it/ do
  get &quot;thankyou&quot;, to: &quot;pages#thankyou&quot;
  get &quot;terms&quot;, to: &quot;pages#terms&quot;

  resource :submissions, only: %i[new create]
  get &quot;submissions&quot;, to: &quot;submissions#new&quot;
  get &quot;/&quot;, to: &quot;submissions#new&quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Field translation&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/barsoom/traco?ref=larsp.de&quot;&gt;Translatable columns for Ruby on Rails, stored in the model table itself&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Gemfile
gem &quot;traco&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;# app/models/question.rb

class Question &amp;lt; ApplicationRecord
  translates :question, :answer
end
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>Ruby on Rails</category></item><item><title>Syncthing</title><link>https://larsp.de/posts/syncthing/</link><guid isPermaLink="true">https://larsp.de/posts/syncthing/</guid><description>Syncthing is a free, open-source file synchronization solution that works across multiple platforms, offering a transparent alternative to cloud services like iCloud and Dropbox.</description><pubDate>Tue, 06 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The best (IMHO) multi-platform open-source file synchronization solution.&lt;/p&gt;
&lt;p&gt;As much I wanted it to work, iCloud file synchronization used to give me headaches. I work with two Macs - one Mini in the office, and a MacBook on the go. In addition, I&apos;m using a large iPad Pro and an older, small iPad Pro for traveling. My work files, mostly Git repositories of projects I am working on and additional reference material, should be shared across all these devices. I tried to use iCloud for this, but it was always a pain to get it to work reliably. I also used Dropbox in the past, but moved away after they went the course of integration everything and whatnot in their software. Also, it was a resource hog.&lt;/p&gt;
&lt;p&gt;The problem with iCloud is that you don&apos;t really know what&apos;s going on. It&apos;s a black box. You can&apos;t see what&apos;s happening, and you can&apos;t really control it. When the service thinks your files might have been changed on another device, it will create a copy of the file with a suffix &quot; 2&quot;. Sometimes this happens for hundreds of files in a folder, and I resorted to just deleting them with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;find . -name &quot;*\ 2&quot; -delete
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, sometimes iCloud is not updating at all for some reason.&lt;/p&gt;
&lt;h2&gt;Enter Syncthing&lt;/h2&gt;
&lt;p&gt;Yesterday, I was fed up with this and installed &lt;a href=&quot;https://github.com/syncthing/syncthing?ref=larsp.de&quot;&gt;Syncthing&lt;/a&gt; on my Macs. It&apos;s a free, open-source file synchronization software that works on all major platforms and works really smoothly. I used it in the past already, and never had a problem.&lt;/p&gt;
&lt;h3&gt;iOS&lt;/h3&gt;
&lt;p&gt;For iOS, there is a very good open source client app called &lt;a href=&quot;https://apps.apple.com/de/app/synctrain/id6553985316?ref=larsp.de&quot;&gt;Synctrain&lt;/a&gt;. There&apos;s also an older third party solution (&lt;a href=&quot;https://www.mobiussync.com/?ref=larsp.de&quot;&gt;MöbiusSync&lt;/a&gt;), but I&apos;d recommend Synctrain because it&apos;s much smoother.&lt;/p&gt;
&lt;p&gt;There is a &lt;a href=&quot;https://github.com/syncthing/syncthing/blob/main/GOALS.md?ref=larsp.de&quot;&gt;goals document&lt;/a&gt; describing Syncthing if you&apos;re interested.&lt;/p&gt;
&lt;h3&gt;Linux install&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install syncthing
sudo systemctl enable syncthing@lape.service
sudo systemctl start syncthing@lape.service
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;CLI commands&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;syncthing cli config devices add --device-id ...
syncthing cli config options relays-enabled set false
find . -name &quot;*sync-conflict*&quot; -print
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Files to ignore&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;(?d).DS_Store
Thumbs.db
desktop.ini
.Trashes
.Spotlight-V100
._*
lost+found
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><category>Tools</category></item><item><title>Archiving CMS websites to static files with httrack</title><link>https://larsp.de/posts/archiving-cms-websites-to-static-files-with-httrack/</link><guid isPermaLink="true">https://larsp.de/posts/archiving-cms-websites-to-static-files-with-httrack/</guid><description>Guide to using httrack to archive CMS websites like Drupal and WordPress to static HTML files when sites are no longer actively maintained or need to be retired from production.</description><pubDate>Wed, 23 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Using httrack to archive a CMS website to keep only as static site.&lt;/p&gt;
&lt;h2&gt;When to Archive CMS Sites&lt;/h2&gt;
&lt;p&gt;When a website built with a content management system like Drupal or WordPress is no longer updated with content or a campaign has ended, the webpages sometimes need to be archived for reference or remain online without further changes. It&apos;s not always feasible to upgrade all CMS components along the way. A major version change might require expensive custom module upgrades for a site no longer in production use. Archiving to static files is a practical solution.&lt;/p&gt;
&lt;h2&gt;Using the httrack tool to archive a website&lt;/h2&gt;
&lt;p&gt;There are several options for archiving websites (see &lt;a href=&quot;https://github.com/iipc/awesome-web-archiving&quot;&gt;Awesome Web Archiving List&lt;/a&gt;). The &lt;a href=&quot;https://www.httrack.com/&quot;&gt;httrack&lt;/a&gt; command line tool is a preferred option. On macOS using Homebrew, install it with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install httrack
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These optimal httrack options for mirroring:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;httrack http://SITE_TO_ARCHIVE -O DESTINATION_DIR \
  -N &quot;%h%p/%n/index%[page].%t&quot; \
  -WqQ%v --robots=0 --footer &apos;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The tool will prompt you if external links should be followed.&lt;/p&gt;
&lt;h2&gt;Post-Processing Steps&lt;/h2&gt;
&lt;p&gt;Relative links can be rewritten afterwards (e.g., &quot;about.html&quot; to &quot;about&quot;). This is optional but useful if you want to preserve URL paths for inbound links.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;find . -name &quot;*.html&quot; -type f -print0 \
  | xargs -0 perl -i -pe &quot;s/\/index.html/\//g&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Copy the homepage index from &lt;code&gt;index/index.html&lt;/code&gt; to the site root and change include paths and links in it (remove &quot;../&quot; everywhere).&lt;/p&gt;
&lt;p&gt;If the source site uses HTTP authentication, provide username and password as part of the URL: &lt;code&gt;username:password@your.url&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Hosting Archived Sites&lt;/h2&gt;
&lt;p&gt;The resulting files can be served from inexpensive static web hosting like Netlify or GitHub Pages.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.httrack.com/html/fcguide.html&quot;&gt;Httrack users guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.drupal.org/node/27882&quot;&gt;Archiving Drupal sites&lt;/a&gt; on &lt;a href=&quot;http://drupal.org&quot;&gt;drupal.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.lullabot.com/articles/sending-drupal-site-retirement-using-httrack&quot;&gt;About archiving Drupal sites&lt;/a&gt; by Karen from Lullabot&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><category>Tools</category><category>Hosting</category></item><item><title>Barcode PDFs with Ruby on Rails</title><link>https://larsp.de/posts/barcode-pdfs-with-ruby-on-rails/</link><guid isPermaLink="true">https://larsp.de/posts/barcode-pdfs-with-ruby-on-rails/</guid><description>A guide to generating individual PDFs with imprinted EAN barcodes using Barby and Prawn libraries in Ruby on Rails projects.</description><pubDate>Sun, 20 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Using Barby and Prawn to imprint PDFs with individual barcodes&lt;/p&gt;
&lt;p&gt;For a &lt;a href=&quot;https://larsp.de/ruby-on-rails-resources/&quot;&gt;Rails&lt;/a&gt; project, I researched methods to generate individual PDFs with imprinted EAN barcodes. This guide documents a working approach using modern Ruby libraries.&lt;/p&gt;
&lt;h2&gt;Libraries Used&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Barby&lt;/strong&gt; is a barcode generator library for Ruby that generates barcodes as images or PDFs. &lt;strong&gt;Prawn&lt;/strong&gt; is a PDF generation library for Ruby that creates PDFs from scratch and annotates existing PDFs with text, images, and barcodes.&lt;/p&gt;
&lt;h2&gt;Implementation Approach&lt;/h2&gt;
&lt;p&gt;The solution uses two model classes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A voucher class with a &lt;code&gt;code&lt;/code&gt; property (printed as a barcode)&lt;/li&gt;
&lt;li&gt;A PDF generation class that subclasses &lt;code&gt;Prawn::Document&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The PDF generation class accepts a path and code as arguments, generates a PDF with the barcode imprinted, and returns the path to a temporary file that is automatically deleted when the Rails process exits.&lt;/p&gt;
&lt;h2&gt;PDF Specifications&lt;/h2&gt;
&lt;p&gt;The resulting PDF is 100mm x 133mm with a PNG background image. Initially, the &lt;code&gt;background&lt;/code&gt; option of &lt;code&gt;Prawn::Document&lt;/code&gt; was tested but didn&apos;t scale the image properly. Instead, the &lt;code&gt;image&lt;/code&gt; method with the &lt;code&gt;fit&lt;/code&gt; option scales the image to the page size.&lt;/p&gt;
&lt;p&gt;Prawn&apos;s &lt;code&gt;measurement_extensions&lt;/code&gt; allow using millimeters as a unit instead of the default 1/72 inch.&lt;/p&gt;
&lt;h2&gt;Code Example&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;require &quot;barby/barcode/code_128&quot;
require &quot;barby/outputter/prawn_outputter&quot;
require &quot;prawn/measurement_extensions&quot;

class CodePdf &amp;lt; Prawn::Document
  def initialize path, code, background
    super({
      page_size: [100.mm, 177.mm],
      margin: 0
    })

    image background, fit: [100.mm, 177.mm]
    barcode code
    render_file path
  end

  def barcode code
    barcode = Barby::Code128.new code
    barcode.annotate_pdf self, height: 18.mm, x: 17.mm, y: 3.mm
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Voucher Generation&lt;/h2&gt;
&lt;p&gt;In the code class, a temporary file is created and the PDF generation class is called. The background image is located in the &lt;code&gt;app/assets/images/{language}&lt;/code&gt; directory. The &lt;code&gt;I18n.locale&lt;/code&gt; method returns the current locale (e.g., &lt;code&gt;de&lt;/code&gt; or &lt;code&gt;fr&lt;/code&gt;) to find the correct background image:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def voucher
  # Create temporary file e.g. tmp/voucher20230805-66997-kozjms.pdf
  tmpfile = Tempfile.new &quot;voucher&quot;, Rails.root.join(&quot;tmp&quot;)
  path = tmpfile.path + &quot;.pdf&quot;
  bg_path = Rails.root.join &quot;app&quot;, &quot;assets&quot;, &quot;images&quot;, I18n.locale.to_s, price.voucher
  CodePdf.new path, code, bg_path
  path
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is an example of the resulting voucher PDF with the barcode:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/posts/barcode-pdfs-with-ruby-on-rails/voucherpdf.png&quot; alt=&quot;Example voucher PDF with imprinted barcode&quot; /&gt;&lt;/p&gt;
</content:encoded><category>Ruby on Rails</category></item></channel></rss>