Curated library of AI agent skills for Ruby on Rails development. Covers code review, architecture, security, testing (RSpec), engines, service objects, DDD patterns, and workflow automation.
98
99%
Does it follow best practices?
Impact
98%
1.38xAverage score across 26 eval scenarios
Passed
No known issues
Use this skill when designing, implementing, or reviewing GraphQL APIs in a Rails application with the graphql-ruby gem.
Tests gate implementation — write specs before resolver code (see rspec-best-practices).
Before shipping a resolver/mutation slice, ALL of the following must be true (details in linked sections; do not duplicate checks in prose here):
- N+1 Prevention: use `dataloader.with(Source, Model).load(id)` — NEVER `object.association`
- Authorization: sensitive fields have field-level guards (not type-level alone).
- Type Conventions: paginated collections use Types::*Type.connection_type, not plain arrays.
- Schema safeguards: AppSchema disables introspection in production and sets max_depth / max_complexity.
- TESTING.md: specs in `spec/graphql/` use `AppSchema.execute` — **ALL spec files** (resolver specs AND mutation specs). Never use HTTP controller dispatch for GraphQL specs.
- Error Handling: mutations return `{ result, errors }` with rescue blocks — no unhandled exceptions.
- Documentation: `description:` on every field in every type.
- Resolver Structure: dedicated resolver classes, not inline field blocks.1. SPEC: Write failing spec (happy path + auth + validation error case) — see TESTING.md
2. TYPE: Arguments and return types — Type Conventions for pagination shape
3. IMPLEMENT: Resolver/mutation class delegating to a service object
4. N+1 CHECK: N+1 Prevention (dataloader on every association load from GraphQL)
5. AUTH CHECK: Authorization (field-level guards where data is sensitive)
6. FINAL CHECK: Verify every HARD-GATE item above against the code you wrote — all 8 must be true
7. RUN: Full suite green before PRDO NOT proceed to step 3 before step 1 is written and failing.
connection_type, never a plain array of nodes.field :orders, Types::OrderType.connection_type, null: false, resolver: Resolvers::Orders::ListResolverQueryType and MutationType as entry points only — delegate: field :summary, resolver: Resolvers::Orders::SummaryResolver.bullet gem in development — treat GraphQL N+1s as Critical severity.expect { }.to make_database_queries(count: N) using db-query-matchers.FORBIDDEN: Never call object.buyer, object.user, or any association directly — every association load MUST use the dataloader (graphql-ruby 1.12+):
# ❌ causes N+1 for every record in the list
def buyer; object.buyer; end
# ✅ batches loads across all records
def buyer
dataloader.with(Sources::RecordById, Buyer).load(object.buyer_id)
endSource class definition:
# app/graphql/sources/record_by_id.rb
class Sources::RecordById < GraphQL::Dataloader::Source
def initialize(model_class)
@model_class = model_class
end
def fetch(ids)
records = @model_class.where(id: ids).index_by(&:id)
ids.map { |id| records[id] }
end
endType-level auth alone is insufficient — add field-level guards for sensitive fields:
field :internal_notes, String, null: true do
guard -> (_obj, _args, ctx) { ctx[:current_user]&.admin? }
endFor Pundit: authorize! object, to: :read?, with: OrderPolicy in the resolver's resolve method.
Configure production introspection and query limits on AppSchema in one place:
class AppSchema < GraphQL::Schema
disable_introspection_entry_points if Rails.env.production?
max_depth 10
max_complexity 300
endAdjust depth/complexity to your API; document the chosen limits in the PR or schema comments if non-default.
Mutations must return a structured response — never raise unhandled exceptions to the client:
class Mutations::CreateOrder < Mutations::BaseMutation
argument :product_id, ID, required: true
field :order, Types::OrderType, null: true
field :errors, [String], null: false
def resolve(product_id:)
result = Orders::CreateOrder.call(user: context[:current_user], product_id: product_id)
result.success? ? { order: result.order, errors: [] } : { order: nil, errors: result.errors }
rescue ActiveRecord::RecordInvalid => e
{ order: nil, errors: e.record.errors.full_messages }
rescue StandardError => e
Rails.logger.error("Mutation failed: #{e.class}: #{e.message}")
{ order: nil, errors: ['An unexpected error occurred'] }
end
endSee TESTING.md for the spec template, paths, and checklist (happy path, unauthenticated, unauthorized, validation errors, N+1 counts, limits).
Write description: inline on every field in every type — no field left undescribed:
class Types::OrderType < Types::BaseObject
description "A customer order containing one or more line items."
field :id, ID, null: false, description: "Unique identifier."
field :status, String, null: false, description: "Current order status: pending, confirmed, shipped, delivered."
field :total_cents, Integer, null: false, description: "Total order amount in cents."
end| Skill | When to chain |
|---|---|
| ddd-ubiquitous-language | Type and field naming must match business language |
| rails-tdd-slices | Choose first failing spec (mutation vs query vs resolver unit) |
| rspec-best-practices | Full TDD cycle for resolvers and mutations |
| rails-security-review | Auth, introspection disable, query depth/complexity limits |
api-rest-collection
create-prd
ddd-boundaries-review
ddd-rails-modeling
ddd-ubiquitous-language
docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10
scenario-11
scenario-12
scenario-13
scenario-14
scenario-15
scenario-16
scenario-17
scenario-18
scenario-19
scenario-20
scenario-21
scenario-22
scenario-23
scenario-24
scenario-25
scenario-26
generate-tasks
mcp_server
rails-architecture-review
rails-background-jobs
rails-bug-triage
rails-code-conventions
rails-code-review
rails-engine-compatibility
rails-engine-docs
rails-engine-extraction
rails-engine-installers
rails-engine-release
rails-engine-reviewer
rails-engine-testing
rails-graphql-best-practices
rails-migration-safety
rails-review-response
rails-security-review
rails-skills-orchestrator
rails-stack-conventions
rails-tdd-slices
refactor-safely
rspec-best-practices
rspec-service-testing
ruby-service-objects
strategy-factory-null-calculator
ticket-planning
yard-documentation