activerecord

ruby
class User < ApplicationRecord
  has_many :posts, foreign_key: :author_id, dependent: :destroy

  before_validation :normalize_email
  before_create :generate_auth_token
  after_create :send_welcome_email

ActiveRecord callbacks for lifecycle hooks

rails activerecord patterns
by Alex Kumar 1 tab
ruby
class AddUniqueIndexToTags < ActiveRecord::Migration[7.1]
  disable_ddl_transaction!

  def up
    execute <<~SQL
      UPDATE tags SET name = LOWER(TRIM(name)) WHERE name IS NOT NULL;

Safer “find or create” with Unique Constraint + Retry

rails activerecord concurrency
by codesnips 3 tabs
ruby
class ExplainAnalyzer
  def initialize(relation, watched_tables:)
    @relation = relation
    @watched_tables = Array(watched_tables).map(&:to_s)
  end

Fast Fail for Missing Indexes (EXPLAIN sanity check)

rails postgres performance
by codesnips 3 tabs
ruby
module RetryableTransaction
  module_function

  RETRIABLE = [ActiveRecord::Deadlocked, ActiveRecord::LockWaitTimeout].freeze

  def run(max_retries: 3, base_delay: 0.05, &block)

Deadlock-Aware Retry Wrapper

rails postgres reliability
by codesnips 3 tabs
ruby
class CreateMaintenanceTasks < ActiveRecord::Migration[7.0]
  def change
    create_table :maintenance_tasks do |t|
      t.string :name, null: false
      t.string :state, null: false, default: "pending"
      t.datetime :started_at

Database-Backed “Run Once” Migrations for Maintenance Tasks

rails migrations background-jobs
by codesnips 3 tabs
ruby
class CreateEmailDeliveries < ActiveRecord::Migration[7.1]
  def change
    create_table :email_deliveries do |t|
      t.string :dedupe_key, null: false
      t.string :mailer, null: false
      t.string :action, null: false

Transactional Email “Send Once” with Delivered Marker

rails reliability activerecord
by codesnips 4 tabs
ruby
class AtLeastOneOfValidator < ActiveModel::Validator
  def validate(record)
    fields = Array(options[:fields])
    raise ArgumentError, "provide :fields" if fields.empty?

    return if fields.any? { |field| filled?(record.public_send(field)) }

Custom Validator for “At Least One of” Fields

rails activemodel validations
by codesnips 3 tabs
ruby
module ExistenceChecks
  extend ActiveSupport::Concern

  class_methods do
    def has_any?(conditions = {})
      relation = conditions.present? ? where(conditions) : all

Fast “Exists” Checks with select(1) and LIMIT

rails activerecord performance
by codesnips 4 tabs
ruby
class NotifyFollowersJob
  include Sidekiq::Job

  sidekiq_options queue: :notifications, retry: 5

  def perform(post_id, actor_id)

Safer Background Job Arguments (Serialize IDs only)

rails reliability sidekiq
by codesnips 3 tabs
ruby
class AddUniqueIndexToInventorySnapshots < ActiveRecord::Migration[7.1]
  disable_ddl_transaction!

  def change
    add_index :inventory_snapshots,
              [:warehouse_id, :sku],

Bulk Upsert with insert_all + Unique Index

rails activerecord postgres
by codesnips 3 tabs
ruby
class Article < ApplicationRecord
  scope :ranked, -> { order(score: :desc, id: :desc) }

  scope :after_cursor, ->(cursor) do
    return all if cursor.nil?

Deterministic Sorting with Secondary Key

rails activerecord pagination
by codesnips 4 tabs
sql
-- Product.active.touch_all(:cache_synced_at) for catalog 42
UPDATE "products"
SET "updated_at" = '2024-05-01 12:00:00.123456',
    "cache_synced_at" = '2024-05-01 12:00:00.123456'
WHERE "products"."catalog_id" = 42
  AND "products"."status" = 'active';

Use `touch_all` for Efficient “Bump Updated At”

rails activerecord performance
by codesnips 4 tabs