Use when you have a written implementation plan to execute in a separate session with review checkpoints
npx skills add phrazzld/claude-config --skill "ruby-conventions"
Install specific skill from multi-skill repository
# Description
|
# SKILL.md
name: ruby-conventions
description: |
Ruby and Rails best practices for services, testing, and architecture. Use when:
- Writing or reviewing Ruby/Rails code
- Designing service objects or organizing business logic
- Setting up RSpec tests with FactoryBot
- Building APIs with JSON serialization
- Optimizing Rails performance (N+1, caching)
Keywords: Ruby, Rails, RSpec, FactoryBot, service object, strong params,
N+1 query, Sidekiq, RuboCop, Thor CLI
Ruby Conventions
Service objects, strong params, behavior-focused tests.
Architecture
Service objects for business logic:
# app/services/user_registration_service.rb
class UserRegistrationService
def initialize(user_params:, mailer: UserMailer)
@user_params = user_params
@mailer = mailer
end
def call
user = User.create!(@user_params)
@mailer.welcome(user).deliver_later
user
end
end
Thin controllers:
def create
user = UserRegistrationService.new(user_params: user_params).call
render json: UserSerializer.new(user), status: :created
rescue ActiveRecord::RecordInvalid => e
render json: { errors: e.record.errors }, status: :unprocessable_entity
end
Strong Parameters
Always use strong params. Never mass-assign directly:
# Good
def user_params
params.require(:user).permit(:email, :name, :password)
end
# Never
User.create(params[:user]) # SQL injection risk
Query Safety
Always parameterize queries:
# Good
User.where(email: email)
User.where("email = ?", email)
# Never
User.where("email = '#{email}'") # SQL injection
Prevent N+1 queries:
# Good
User.includes(:posts).each { |u| u.posts.count }
# Bad (N+1)
User.all.each { |u| u.posts.count }
Testing with RSpec
RSpec.describe UserRegistrationService do
describe "#call" do
it "creates active user with welcome email" do
mailer = instance_double(UserMailer)
allow(mailer).to receive(:welcome).and_return(double(deliver_later: true))
service = described_class.new(
user_params: { email: "[email protected]", name: "Test" },
mailer: mailer
)
user = service.call
expect(user).to be_persisted
expect(user.email).to eq("[email protected]")
expect(mailer).to have_received(:welcome).with(user)
end
end
end
Use FactoryBot, not fixtures:
FactoryBot.define do
factory :user do
email { Faker::Internet.email }
name { Faker::Name.name }
end
end
let(:user) { create(:user) }
API Design
# Consistent serialization
class UserSerializer
include JSONAPI::Serializer
attributes :id, :email, :name, :created_at
end
# Versioned routes
namespace :api do
namespace :v1 do
resources :users
end
end
Language Patterns
# Keyword arguments for 2+ params
def send_email(to:, subject:, body:)
...
end
# Safe navigation
user&.profile&.avatar_url
# Frozen strings (file header)
# frozen_string_literal: true
Anti-Patterns
- Fat models (business logic in ActiveRecord)
- Business logic in controllers
- Fixtures instead of factories
- Testing implementation (mocking internals)
- String interpolation in SQL
- N+1 queries without includes
- Synchronous email in request cycle
References
- rails-performance.md - Caching, background jobs, profiling
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.