Skip to content

SYSTEM

Ruby on Rails

Ruby on Rails is the dominant Ruby web-application framework (David Heinemeier Hansson, 2004). Canonical MVC web framework with ActiveRecord ORM, convention-over-configuration defaults, and a large ecosystem of companion gems for background jobs (Sidekiq), feature flags (Flipper), testing (Minitest / RSpec / FactoryBot), and SAML auth (ruby-saml).

Why it matters here

PlanetScale's application-tier backend is a Rails monolith. Multiple Rails-specific engineering posts have surfaced on the wiki:

Rails is also the substrate most SidekiqMiddleware::* code lives in — client middleware runs inside Rails request processes (or console sessions or rake tasks), server middleware inside Sidekiq worker processes that boot the same Rails app.

Seen in

  • — canonical wiki introduction of Rails 7's query_log_tags native feature + the ActiveRecord annotate per-query method + PlanetScale's activerecord-sql_commenter gem that swaps the Rails-default tag format for SQLCommenter. Also surfaces the Marginalia gem as the Rails-6-and-earlier pre-history of the framework-absorbed feature. Together these establish Rails as the canonical ORM-layer-query-tag-propagation substrate on the wiki (patterns/query-comment-tag-propagation-via-orm).
  • — Rails .underscore class-name convention used to derive per-job-class Flipper flag names (InvoiceJobdisable_invoice_job).
  • — Rails test-suite parallelism + FactoryBot audit on CI.
  • — Rails substrate for PlanetScale's self-healing-Sidekiq architecture: ActiveRecord with_lock (row-level SELECT FOR UPDATE), in_batches cursor iteration for bulk scheduler enqueue, ActiveJob's set(wait:).perform_later API composed into perform_with_jitter on ApplicationJob. The scheduler pattern and idempotent-job discipline sit on top of these Rails-framework primitives.

Seen in — ActiveRecord query-rewriter gems

  • — Mike Coutermarsh's 2022 introduction of PlanetScale's fast_page gem. Rails is the substrate for the ORM-level SQL-rewriter gem pattern: a method added to ActiveRecord::Relation mechanically transforms a query chain into a more efficient equivalent — here, the deferred-join rewrite for deep-offset pagination. The post's canonical usage pattern is Rails-idiomatic method-chain composition: Post.all.order(created_at: :desc).limit(25).offset(100).fast_page. Cross-ecosystem companion: Hammerstone's Laravel fast-paginate gem implements the same rewrite for Eloquent. Both gems confirm the broader observation that the ORM-query-rewriter pattern is ecosystem-portable — the rewrite is SQL-level, the gem is just the ergonomic wrapper.

Seen in — multi-database config + automatic role switching

  • — Taylor Barnett's PlanetScale Portals launch uses Rails' multiple-databases / automatic role switching as the canonical application-side integration for a read- write-split + regional read replica architecture. Three Rails-specific mechanisms are load-bearing in the post:

  • database.yml multi-connectionprimary (write connection) + primary_replica (read connection with replica: true). Rails treats primary_replica as a read-only sibling of primary for monitoring / migration purposes.

  • connected_to(role: :reading) do … end — explicit per-block routing for code that wants to force replica reads.
  • ActiveRecord::Middleware::DatabaseSelector with { delay: 2.seconds } — automatic role switching. Reads go to primary_replica by default; after any write, a session cookie pins the user's reads back to primary for 2 seconds, preserving read-your-writes.

The Rails invocation is the canonical framework-level shape of the patterns/session-cookie-for-read-your-writes pattern — see that pattern page for the full recipe and equivalents in Django / Laravel / plain-driver apps. Code acknowledgment to Mike Coutermarsh (same PlanetScale-Rails engineer voice as the FastPage / SQLCommenter / self-healing- Sidekiq posts).

Seen in — application-generated public IDs via ActiveSupport concern

  • — Mike Coutermarsh (PlanetScale, 2022-03-29) discloses the full Rails PublicIdGenerator ActiveSupport concern that generates 12-char base-36 NanoIDs as the externally-visible public_id column on every public-facing PlanetScale model. Rails-specific primitives that are load-bearing:

  • ActiveSupport::Concern — the shared-module mechanism for include PublicIdGenerator in models that need the pattern. Canonical Rails code-reuse idiom.

  • before_create :set_public_id — ActiveRecord callback firing exactly once per row insert, before the INSERT SQL is issued so the public_id is populated at INSERT time (not UPDATE-later).
  • self.class.where(public_id: public_id).exists? — pre-insert duplicate check for the bounded-retry correctness contract. (The real correctness primitive is the DB-side UNIQUE KEY idx_public_id; the Rails check is a UX optimisation.)
  • include PublicIdGenerator model declaration — the one-line activation of the concern per-model.

This is the canonical public-id-alongside-BIGINT-PK pattern realised on Rails, with full source code disclosure + matching Go publicid package for cross-language consistency. Rails is the substrate for the PublicIdGenerator concern + the schema shape (id BIGINT AUTO_INCREMENT PRIMARY KEY + public_id VARCHAR(12) UNIQUE KEY). Coutermarsh's first wiki ingest as a PlanetScale author — earlier than his FastPage / SQLCommenter / self-healing-Sidekiq / Portals work.

Seen in — ActiveRecord migrations + schema-change workflow

  • — Mike Coutermarsh (PlanetScale, 2023-03-20) canonicalises the Rails migration workflow on PlanetScale via the planetscale_rails gem. Rails primitives that are load-bearing in the workflow:

  • db/migrate/*.rb — ActiveRecord migration files with up / down / change methods. Authored once, run against a PlanetScale dev branch via rake psdb:migrate, shipped to production through a deploy request.

  • schema.rb — the canonical serialised schema snapshot. Updated by psdb:migrate and committed alongside the migration file in the same PR.
  • ActiveRecord::Base.ignored_columns — the bridge primitive for column drops. Adding self.ignored_columns += %w(category) tells ActiveRecord to behave as if the column doesn't exist, so the app ships ahead of the schema change. Canonical Rails idiom for code-before-schema drops per schema-change deploy order.
  • .find_each — batched iteration (default batch size 1,000) for memory-safe bulk data migrations. Load-bearing in the backfill template: Project.all.find_each { |p| p.update(:new_col, p.old_col) } — prevents the naive Project.all.each from materialising every row.
  • Rails console — production-shell entry point for data migrations (not schema migrations). Canonicalised as the correct altitude for data reshape after schema is in place.
  • Multi-database support (Rails 6+) — composes with the gem's psdb:migrate:primary-style suffixes.
  • ActiveRecord callbacks — suggested as the double-write mechanism during the five-step rename- column recipe. The callback fires on save / update, so the new column receives writes alongside the old one during the parallel-change window.

This is the Rails instantiation of PlanetScale's branch- based schema-change workflow. Parallels the earlier Laravel post for PHP. The gem is the framework-specific bridge that makes the platform's deploy-request lifecycle feel native to Rails engineers. Dogfooded on app.planetscale.com before open-sourcing.

Last updated · 542 distilled / 1,571 read