All skills
jeffallan avatar

/rails-expert

@efebc44
by jeffallanjeffallan/claude-skills12k stars
1,124

Rails 7+ specialist that optimizes Active Record queries with includes/eager_load, implements Turbo Frames and Turbo Streams for partial page updates, configures Action Cable for WebSocket connections, sets up Sidekiq workers for background job processing, and writes comprehensive RSpec test suites. Use when building Rails 7+ web applications with Hotwire, real-time features, or background job processing. Invoke for Active Record optimization, Turbo Frames/Streams, Action Cable, Sidekiq, RSpec Rails.

Use this Skill: https://skilld.dev/gh/jeffallan/claude-skills/rails-expert

This session only. Nothing lands on disk.

referencesactive-record.md

≈1.4k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Active Record Patterns

Model Associations

# app/models/user.rb
class User < ApplicationRecord
  has_many :posts, dependent: :destroy
  has_many :comments, dependent: :destroy
  has_many :commented_posts, through: :comments, source: :post

  has_one :profile, dependent: :destroy
  has_one_attached :avatar
  has_many_attached :documents

  validates :email, presence: true, uniqueness: true
  validates :username, presence: true, length: { minimum: 3, maximum: 50 }

  before_save :normalize_email

  private

  def normalize_email
    self.email = email.downcase.strip
  end
end

# app/models/post.rb
class Post < ApplicationRecord
  belongs_to :user
  has_many :comments, dependent: :destroy
  has_many :taggings, dependent: :destroy
  has_many :tags, through: :taggings

  scope :published, -> { where(published: true) }
  scope :recent, -> { order(created_at: :desc) }
  scope :by_user, ->(user) { where(user: user) }

  validates :title, presence: true, length: { maximum: 200 }
  validates :body, presence: true
end

Query Optimization

Prevent N+1 queries:

# Bad - N+1 query
@posts = Post.all
@posts.each { |post| puts post.user.name }

# Good - eager loading
@posts = Post.includes(:user)
@posts.each { |post| puts post.user.name }

# Multiple associations
@posts = Post.includes(:user, :comments, :tags)

# Nested associations
@posts = Post.includes(comments: :user)

# Use joins when you don't need the associated records
@posts = Post.joins(:user).where(users: { active: true })

Query scopes:

class Post < ApplicationRecord
  scope :published, -> { where(published: true) }
  scope :recent, ->(limit = 10) { order(created_at: :desc).limit(limit) }
  scope :by_tag, ->(tag) { joins(:tags).where(tags: { name: tag }) }
  scope :search, ->(query) { where("title ILIKE ?", "%#{sanitize_sql_like(query)}%") }

  # Class method for complex logic
  def self.trending(days = 7)
    where("created_at > ?", days.days.ago)
      .joins(:comments)
      .group(:id)
      .order("COUNT(comments.id) DESC")
  end
end

# Usage
Post.published.recent(5)
Post.by_tag("rails").search("hotwire")

Advanced Queries

# Select specific columns
Post.select(:id, :title, :created_at)

# Count and group
User.joins(:posts).group(:id).count
User.joins(:posts).group("users.id").select("users.*, COUNT(posts.id) as posts_count")

# Pluck for arrays
User.pluck(:email)
User.pluck(:id, :email) # Returns array of arrays

# Find by SQL
Post.find_by_sql("SELECT * FROM posts WHERE title ILIKE '%rails%'")

# Exists?
Post.where(published: true).exists?

# Batch processing
User.find_each(batch_size: 1000) do |user|
  user.process_something
end

Callbacks

class User < ApplicationRecord
  before_validation :normalize_email
  after_validation :log_errors

  before_create :generate_token
  after_create :send_welcome_email

  before_save :update_slug
  after_save :clear_cache

  before_destroy :cleanup_associations
  after_destroy :log_deletion

  # Avoid callbacks for business logic - use service objects instead

  private

  def normalize_email
    self.email = email.downcase.strip if email.present?
  end

  def generate_token
    self.token = SecureRandom.hex(32)
  end
end

Validations

class Article < ApplicationRecord
  validates :title, presence: true, length: { minimum: 5, maximum: 200 }
  validates :slug, uniqueness: { case_sensitive: false }
  validates :published_at, comparison: { greater_than: Time.current }, if: :published?

  validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
  validates :age, numericality: { greater_than_or_equal_to: 18 }

  validate :validate_future_date

  private

  def validate_future_date
    if published_at.present? && published_at < Time.current
      errors.add(:published_at, "must be in the future")
    end
  end
end

Migrations

# db/migrate/20231214_create_posts.rb
class CreatePosts < ActiveRecord::Migration[7.1]
  def change
    create_table :posts do |t|
      t.string :title, null: false
      t.text :body, null: false
      t.boolean :published, default: false, null: false
      t.references :user, null: false, foreign_key: true

      t.timestamps
    end

    add_index :posts, :published
    add_index :posts, [:user_id, :created_at]
  end
end

# Adding columns
class AddSlugToPosts < ActiveRecord::Migration[7.1]
  def change
    add_column :posts, :slug, :string
    add_index :posts, :slug, unique: true
  end
end

# Data migration
class BackfillUsernames < ActiveRecord::Migration[7.1]
  def up
    User.where(username: nil).find_each do |user|
      user.update_column(:username, "user_#{user.id}")
    end
  end

  def down
    # Usually not needed for data migrations
  end
end

Concerns

# app/models/concerns/sluggable.rb
module Sluggable
  extend ActiveSupport::Concern

  included do
    before_validation :generate_slug
    validates :slug, presence: true, uniqueness: true
  end

  private

  def generate_slug
    self.slug ||= title.parameterize if title.present?
  end
end

# Usage in model
class Post < ApplicationRecord
  include Sluggable
end

Performance Tips

  • Add database indexes for frequently queried columns
  • Use counter_cache for associations
  • Use select to limit columns returned
  • Use pluck instead of map for single attributes
  • Use find_each for batch processing large datasets
  • Use database views for complex queries
  • Consider materialized views for expensive aggregations

Source: SKILL.md on GitHub

1 alert16d5 checks · Risk CRITICAL
  • Gen Agent Trust Hub16d

    The skill provides specialist guidance for Rails 7 development, including Active Record optimization, Hotwire integration, and API design. Automated security scans flagged the author's documentation URL and the skill manifest as malicious, likely due to standard development code snippets and GitHub Pages reputation. Manual analysis confirms these are legitimate vendor resources and development templates. The skill includes strong safety guidelines, such as mandatory SQL sanitization, to promote secure coding.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    6 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at efebc44. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 5 months ago
Other metadata
metadata
{
  "author": "https://github.com/Jeffallan",
  "version": "1.1.0",
  "domain": "backend",
  "triggers": "Rails, Ruby on Rails, Hotwire, Turbo Frames, Turbo Streams, Action Cable, Active Record, Sidekiq, RSpec Rails",
  "role": "specialist",
  "scope": "implementation",
  "output-format": "code",
  "related-skills": "fullstack-guardian, database-optimizer"
}

README badge

README badge for jeffallan/claude-skills/rails-expert