Active Storage Is a Boundary Decision
See how Active Storage balances local simplicity, durable object storage, and preview-processing dependencies so you can choose the right boundary for a Rails file workflow.
Loading…
Topic
10 posts about Rails. Every summary links to the original.
See the idea
See how Active Storage balances local simplicity, durable object storage, and preview-processing dependencies so you can choose the right boundary for a Rails file workflow.
The Good Stuff
Paid picks we use ourselves. Links carry a referral code — a subscription through one earns us a commission at no extra cost to you.
Newest first
Sam Ruby describes publishing an online guide to using Kamal 2.0 for production after finding existing material insufficient for deploying a real project. The guide grew from research for the Deployment and Production chapter of Agile Web Development with Rails 8, then was converted from Pragmatic Programming’s XML grammar to Markdown with GitHub Copilot and proofread with it. It presents an opinionated starter list with defaults and alternatives, covering seven initial requirements alongside Docker builders, container repositories, secret management, hosting choices, load balancing, and managed databases. It also treats production as including database backups, searchable logs, monitoring, and application security, and invites community corrections or additions under a CC0 license.
Fly.io is seeking early-to-mid-level full-stack developers to work on customer-facing parts of its global application-hosting product. The role sits in a CLI-first organization whose UX stack combines Rails, GraphQL, and Go, with more Elixir and Phoenix planned, while the broader platform uses Rust and Go. Candidates are not expected to be Rails or Elixir experts; the stated bar is the ability to learn unfamiliar code and produce work that holds up, including deploying an application end to end and building browser UI components. Hiring centers on untimed work-sample challenges based on the team’s actual work rather than resume screening, interview gauntlets, or gotchas. The remote full-time role offers US healthcare, flexible vacation, hardware and phone allowances, and $120k–$140k plus equity.
Shopify’s Ruby monolith spans 37,000 files, 622,000 methods, and more than 2,000,000 calls, making fast feedback and stability difficult despite rigorous reviews and 150,000 automated tests. Sorbet was selected after the team evaluated requirements for gradual typing, speed, and support for Ruby and Rails features including metaprogramming, overloading, and class reopening. Its RBI files represent constructs it cannot infer, while per-file sigils allow adoption to progress without blocking development, and SorbetMetrics tracks sigils, typed calls, and method signatures. Shopify treats typing as a product, combining CI enforcement, developer support, surveys, and interviews to guide rollout and measure sentiment. The excerpt reports 80% of monolith files, including tests, at typed: true or higher, with almost half of calls and methods covered and type checking under 15 seconds on developer machines.
Shopify addressed inefficient data access in its multi-tenant Rails application, where auto-incrementing primary keys interleaved records from many shops even though queries usually targeted one shop. InnoDB stores rows in B+ trees and loads pages into a buffer pool, so the team changed orders and other suitable tables to composite primary keys such as [shop_id, order_id] while keeping an auto-incrementing id secondary key and configuring Active Record to use id. Supporting Ghostferry, migration tooling, and data extraction systems also had to accommodate the schema change, with unique secondary constraints avoided in some cases because LHM migrations could deadlock. On the most queried table, common queries improved 5–6x, median buffer pool reads fell from 1.8 to 1.2, and elapsed database time dropped roughly one hour per day per shard, while inserts became about 10x slower.
Large Rails monoliths can develop high coupling, low cohesion, cross-component calls, shared Active Record models, and classes that know too much because Ruby and Rails provide limited boundary enforcement. Shopify created Packwerk, an open-source static analysis tool that groups Ruby files into packages and enforces dependency and privacy boundaries, including controlled public APIs for constants. It reports the violation type and location with actionable next steps, integrates with CI, and can run locally; installation begins by adding the gem and running packwerk init. Because Ruby static analysis is complex, Packwerk ignores constants that are not autoloaded, reducing false positives at the cost of false negatives. The excerpt says it runs in six Shopify Rails applications, with 48 packages and 30 boundary enforcements in the core codebase, while adoption also prompted work on dependency inversion.
Shopify describes the ongoing effort to modularize its core Ruby on Rails monolith, which contains more than 2.8 million lines of Ruby and 500,000 commits. The initiative organizes code into independently owned components intended to narrow developer focus, reduce affected test suites, preserve contracts, and clarify operational ownership, while recognizing that large-scale refactoring is also a people problem. The work has already improved exception triage, distributed codebase chores, and design awareness, while its current practices emphasize grassroots participation, tooling, targeted reviews, and a holistic architectural view. Packwerk restricts dependencies for about a third of the 37 main-monolith components. Shopify is pursuing a cleaner dependency graph, componentized Rails applications by default, and isolated component tests, while reserving service extraction for cases such as storefront rendering and credit-card vaulting.
Application databases often retain only current values in Type 1 dimensions, limiting analysis of historical settings such as feature adoption, retention, and switching behavior. The post explains Type 2 dimensional models through Shopify’s need to track users’ admin languages over time, contrasting application-model changes, scheduled database snapshots, and event logging. Its selected implementation uses Rails after_commit callbacks to send created or updated records to Kafka, then transforms that event history into records with valid_from, valid_to, and is_current fields using ETL recipes involving PySpark and dbt. The approach provides the required granularity but can miss changes or events, requires delete handling and data-quality checks, and is presented as an iterative solution; MySQL binlogs are described as a more reliable future source.
Shopify rewrote the server-side Storefront Renderer, which loads Liquid themes and storefront data before returning HTML, because the legacy Rails-monolith implementation had developed stricter performance demands and rising time-to-first-byte as traffic grew. The new single-purpose application separates storefront traffic from checkout, admin, and API traffic, uses active-active replication with dedicated read replicas, and adds mechanisms for high-load resilience. During migration, a Ruby verifier compares status codes, headers, and bodies from both implementations, while a custom Lua module on OpenResty samples production traffic and routes requests based on verification results. The rollout had reached more than 90% feature parity, and the new implementation averaged 4x faster server response times, with ongoing work aimed at full parity and retiring the legacy system.
Shopify’s Rails monolith needed to add native product videos and 3D models while continuing to support an image infrastructure containing more than 7 billion images. The design question was whether media creation should rely on Active Record callbacks or an explicit pipeline, with transactions protecting interdependent database writes. Callbacks were quick for simple cases, but adding media-specific behavior such as video thumbnails spread conditionals across models and made lifecycle ordering difficult to follow and debug. The pipeline design routes requests through a single Product Create Media Service and media handlers, each organized into before_transaction, during_transaction, and after_transaction steps, while confining logic to one media type. This structure separates concerns, controls creation order, limits model access, and makes implementation details easier to understand and maintain as the feature grows.
Service-oriented Rails applications can use Kafka to move high-volume events between producers and consumers without coupling downstream availability to an upstream request. Kafka persists events for a configured period, lets consumers manage offsets, and distributes replicated data across broker partitions, while ordering is guaranteed within a partition rather than across a topic. The post shows a Rails setup using the ruby-kafka gem, an asynchronous producer, JSON payloads, topics, and partition keys, then applies the event stream to order creation, email, and fulfillment workflows. It also addresses operational concerns including consumer scaling, lag metrics, duplicate delivery, idempotent processing with UPSERTs or event identifiers, and schema evolution, contrasting JSON’s accessibility with Avro’s stronger schema support.
The best engineering reads, once a week.