Curated library of 41 public AI agent skills for Ruby on Rails development. Organized by category: planning, testing, code-quality, ddd, engines, infrastructure, api, patterns, context, and orchestration. Covers code review, architecture, security, testing (RSpec), engines, service objects, DDD patterns, and TDD automation. Repository workflows remain documented in GitHub but are intentionally excluded from the Tessl tile.
95
93%
Does it follow best practices?
Impact
96%
1.77xAverage score across 41 eval scenarios
Passed
No known issues
Complete examples for identifying and fixing performance bottlenecks.
# Bad - N+1 query
Post.all.each do |post|
puts post.author.name # Query for each author!
end
# => 1 query for posts + N queries for authors# Good - includes eager loads
Post.includes(:author).each do |post|
puts post.author.name
end
# => 2 queries total (posts + authors)
# For nested associations
Post.includes(author: :profile, comments: :user).each do |post|
puts post.author.name
puts post.author.profile.bio
post.comments.each { |c| puts c.user.name }
end# Use includes (eager load) - separate queries, works with all associations
Post.includes(:author).where("authors.name LIKE ?", "%John%").references(:author)
# Use preload - always separate queries, ignores conditions on associations
Post.preload(:author).where(published: true)
# Use joins - single query with INNER JOIN, duplicates parent rows
Post.joins(:comments).where(comments: { approved: true }).distinct
# Use left_outer_joins - includes records without associations
Post.left_outer_joins(:comments).where(comments: { id: nil }) # posts without comments<%# app/views/posts/show.html.erb %>
<% cache @post do %>
<h1><%= @post.title %></h1>
<p><%= @post.body %></p>
<p>By <%= @post.author.name %></p>
<% end %><%# app/views/posts/show.html.erb %>
<% cache @post do %>
<article>
<h1><%= @post.title %></h1>
<% cache ["comments", @post.comments.maximum(:updated_at)] do %>
<section class="comments">
<%= render @post.comments %>
</section>
<% end %>
</article>
<% end %><%# app/views/posts/index.html.erb %>
<%= render partial: "post", collection: @posts, cached: true %># Expensive computation cache
def calculate_user_score(user_id)
Rails.cache.fetch("user_score/#{user_id}", expires_in: 1.hour) do
ExpensiveScoreCalculator.call(user_id)
end
end
# With race condition protection
Rails.cache.fetch("hot_data", race_condition_ttl: 10.seconds) do
fetch_from_slow_api
end# Bad - loads all columns
User.all.map(&:id)
# Good - only load id
User.pluck(:id)
# Multiple columns
User.pluck(:id, :email, :name)
# With conditions
User.where(active: true).pluck(:email)# Bad - loads all into memory
User.all.each do |user|
user.update!(last_seen: Time.now)
end
# Good - process in batches
User.find_each(batch_size: 100) do |user|
user.update!(last_seen: Time.now)
end
# With start point for resuming
User.where("id > ?", last_processed_id).find_each do |user|
process(user)
end# Check query plan in Rails console
puts User.where(email: 'test@example.com').explain
# Detailed analysis
result = ActiveRecord::Base.connection.execute(<<-SQL)
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT * FROM posts WHERE user_id = 1
SQL
puts JSON.pretty_generate(JSON.parse(result.first["QUERY PLAN"]))# config/environments/development.rb
config.after_initialize do
Bullet.enable = true
Bullet.alert = true # JavaScript alert
Bullet.bullet_logger = true # Log to bullet.log
Bullet.console = true # Browser console
Bullet.rails_logger = true # Rails log
Bullet.add_footer = true # Add footer to HTML
end# spec/requests/posts_spec.rb
RSpec.describe "Posts", type: :request do
it "does not produce N+1 queries" do
create_list(:post, 5, :with_author)
expect {
get posts_path
}.to make_database_queries(count: 3) # posts + authors + count
end
end# spec/support/matchers/query_count.rb
RSpec::Matchers.define :make_database_queries do |count:|
match do |block|
query_count = 0
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |*|
query_count += 1
end
block.call
query_count == count
ensure
ActiveSupport::Notifications.unsubscribe(subscriber)
end
enddocs
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
scenario-27
scenario-28
scenario-29
scenario-30
scenario-31
scenario-32
scenario-33
scenario-34
scenario-35
scenario-36
scenario-37
scenario-38
scenario-39
scenario-40
scenario-41
mcp_server
skills
api
generate-api-collection
implement-graphql
code-quality
apply-code-conventions
apply-stack-conventions
assets
snippets
code-review
refactor-code
respond-to-review
review-architecture
security-check
context
load-context
setup-environment
ddd
define-domain-language
model-domain
review-domain-boundaries
engines
create-engine
create-engine-installer
document-engine
extract-engine
release-engine
review-engine
test-engine
upgrade-engine
infrastructure
implement-background-job
implement-hotwire
optimize-performance
review-migration
seed-database
version-api
orchestration
skill-router
patterns
create-service-object
implement-calculator-pattern
write-yard-docs
planning
create-prd
generate-tasks
plan-tickets
testing
plan-tests
test-service
triage-bug
write-tests
workflows