Agent skill
rails-graphql-patterns
Analyzes and recommends GraphQL patterns for Rails using graphql-ruby including schema design, types, resolvers, mutations, subscriptions, DataLoader, and query complexity. Use when building GraphQL APIs, defining types, writing mutations, optimizing N+1 queries, or structuring app/graphql. NOT for REST API controllers, ActiveRecord queries outside GraphQL, or Turbo Stream responses.
Install this agent skill to your Project
npx add-skill https://github.com/ag0os/rails-dev-plugin/tree/main/skills/rails-graphql-patterns
SKILL.md
Rails GraphQL Patterns
Analyze and recommend patterns for building GraphQL APIs in Rails with graphql-ruby.
Follow standard graphql-ruby conventions for type definitions, input types, enum types, query types, and basic mutations. This skill focuses on non-obvious patterns and opinionated decisions.
Core Principles
- Batch loading: Always use DataLoader to prevent N+1 queries — never resolve associations directly
- Structured errors: Return error arrays in mutation payloads, not exceptions
- Field-level authorization: Check permissions per field, not just per query
- Complexity limits: Set
max_complexityandmax_depthon the schema - Null annotations: Be intentional with
null: true/falseon every field
DataLoader for N+1 Prevention
Every association field MUST use DataLoader. Never call object.association directly in a resolver.
class Sources::RecordLoader < GraphQL::Dataloader::Source
def initialize(model_class, column: :id)
@model_class = model_class
@column = column
end
def fetch(ids)
records = @model_class.where(@column => ids).index_by { |r| r.send(@column) }
ids.map { |id| records[id] }
end
end
# Usage in type
def author
dataloader.with(Sources::RecordLoader, User).load(object.user_id)
end
See patterns.md for AssociationLoader and CountLoader variants.
Connection Types (Pagination)
Always use connection types for list fields — never return unbounded arrays.
module Types
class PostConnectionType < GraphQL::Types::Connection
edge_type(Types::PostEdgeType)
field :total_count, Integer, null: false
def total_count
object.items.size
end
end
end
# In query type
field :posts, Types::PostConnectionType, null: false, connection: true do
argument :filter, Types::PostFilterInput, required: false
end
Subscriptions — Triggering from Models
# Trigger from model after_create_commit, not from mutations
class Post < ApplicationRecord
after_create_commit :notify_subscribers
private
def notify_subscribers
MyAppSchema.subscriptions.trigger(:post_created, {}, self)
end
end
Schema Configuration
class MyAppSchema < GraphQL::Schema
max_complexity 300
max_depth 15
default_max_page_size 25
use GraphQL::Dataloader
rescue_from ActiveRecord::RecordNotFound do |_err, _obj, _args, _ctx, field|
raise GraphQL::ExecutionError, "#{field.type.unwrap.graphql_name} not found"
end
end
Per-field complexity for expensive operations:
field :expensive_field, String do
complexity 50
end
Anti-Patterns
| Anti-Pattern | Fix |
|---|---|
| N+1 in resolvers | Use DataLoader / Sources |
| No complexity limits | Set max_complexity and max_depth |
| Raising exceptions in mutations | Return { errors: [...] } in payload |
| Authorization only at query root | Check auth at field level |
| Exposing ActiveRecord directly | Define explicit GraphQL types |
| Fat resolvers with business logic | Delegate to service objects |
| No pagination on list fields | Use connection types |
Output Format
When analyzing or creating GraphQL components, provide:
- Type/mutation file with proper null annotations
- DataLoader source if associations are resolved
- Schema configuration (complexity, depth, pagination)
- Test outline executing queries against the schema
- Authorization strategy (context, field-level checks)
Error Handling
- Mutations return
{ resource: nil, errors: [...] }on validation failure - Use
rescue_fromin schema forRecordNotFoundmapped toGraphQL::ExecutionError - Field-level: return
nilor raiseGraphQL::ExecutionErrorfor unauthorized access - Never expose internal error details to clients in production
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
rails-caching-patterns
Caching patterns for Rails applications including fragment caching, low-level caching, HTTP caching, Russian doll caching, and cache invalidation strategies. Automatically invoked when working with Rails.cache, cache stores, stale?/fresh_when, fragment caching, cache keys, or performance optimization through caching. Triggers on "cache", "caching", "Rails.cache", "fragment cache", "Russian doll", "stale?", "fresh_when", "cache key", "cache store", "Redis cache", "Solid Cache", "memcached", "ETag", "cache invalidation", "cache bust". NOT for CDN configuration (use rails-devops-patterns) or database query optimization (use rails-model-patterns).
ruby-object-design
Automatically invoked when making decisions about Ruby code structure and organization. Triggers on "class or module", "should this be a class", "struct vs class", "PORO", "data object", "design pattern", "class vs module", "when to use class", "module vs class", "stateless class", "value object", "data container", "object factory", "extend self", "singleton class". Provides guidance on choosing the right Ruby construct (class, module, Struct, Data, Hash). NOT for code smell identification or refactoring (use ruby-refactoring) or Rails-specific framework patterns.
rails-views-patterns
Analyzes Rails view templates, partials, layouts, helpers, and form patterns for best practices. Use when reviewing ERB templates, improving view performance with fragment caching, fixing form helpers, organizing partials, adding accessibility attributes, or evaluating collection rendering. NOT for Stimulus/Turbo logic (use hotwire-patterns), controller concerns, or API-only responses.
rails-architecture-patterns
Provides architectural planning, design decisions, and coordination guidance for Rails applications. Use when planning new features, choosing between design approaches (STI vs polymorphic, service vs concern, monolith vs engine), evaluating system architecture, or deciding which domain skill or agent to delegate to. NOT for implementation details within a single domain (use the domain-specific skill instead).
rails-mailer-patterns
Action Mailer patterns for Rails applications. Automatically invoked when working with email delivery, mailer classes, email templates, mailer previews, interceptors, or delivery configuration. Triggers on "mailer", "email", "ActionMailer", "deliver_later", "deliver_now", "mail template", "email preview", "SMTP", "SendGrid", "Postmark", "notification email". NOT for push notifications, SMS, or in-app messaging.
rails-devops-patterns
Analyzes Rails deployment, infrastructure, and production configuration for best practices. Use when setting up Docker, writing CI/CD pipelines, configuring Puma, adding monitoring or logging, hardening security (SSL, Rack::Attack, headers), optimizing database config, or reviewing production environment files. NOT for application business logic, model design, or test writing.
Didn't find tool you were looking for?