From ruby-on-rails
This skill should be used when the user is working in a Rails 7+ application and asks about "Rails conventions", "naming conventions", "Rails structure", "Hotwire patterns", "Turbo frames", "Stimulus controllers", "Rails directory structure", "Rails best practices", or needs guidance on idiomatic Rails patterns for production systems.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ruby-on-rails:rails-conventionsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Production-focused guidance for Rails 7+ conventions, naming patterns, directory structure, and modern frontend integration with Hotwire.
Production-focused guidance for Rails 7+ conventions, naming patterns, directory structure, and modern frontend integration with Hotwire.
User, OrderItem, PaymentTransaction)users, order_items, payment_transactions)_id (user_id, order_id)categories_products, roles_users)UsersController, Api::V1::OrdersController)users_controller.rb, api/v1/orders_controller.rb)index, show, new, create, edit, update, destroyPrefer resourceful routes over custom routes:
# Production pattern
resources :orders do
resources :line_items, shallow: true
member do
post :cancel
post :refund
end
collection do
get :pending
end
end
# API versioning
namespace :api do
namespace :v1 do
resources :orders, only: [:index, :show, :create]
end
end
app/views/controller_name/action.html.erb_partial.html.erbapp/views/shared/_partial.html.erbapp/views/components/_button.html.erbapp/
├── assets/
│ └── stylesheets/
├── channels/ # ActionCable channels
├── controllers/
│ ├── concerns/ # Controller concerns
│ └── api/ # API controllers
├── helpers/
├── javascript/
│ └── controllers/ # Stimulus controllers
├── jobs/ # ActiveJob classes
├── mailers/
├── models/
│ └── concerns/ # Model concerns
├── views/
│ ├── layouts/
│ ├── shared/
│ └── components/ # View components (if using)
config/
├── initializers/
├── locales/
└── environments/
db/
├── migrate/
└── seeds.rb
lib/
├── tasks/ # Rake tasks
└── templates/ # Generator templates
spec/ or test/
Place in app/services/ with clear naming:
# app/services/orders/create_service.rb
module Orders
class CreateService
def initialize(user:, cart:)
@user = user
@cart = cart
end
def call
# Implementation
end
end
end
# Usage: Orders::CreateService.new(user: current_user, cart: @cart).call
Place in app/queries/:
# app/queries/orders/pending_query.rb
module Orders
class PendingQuery
def initialize(relation = Order.all)
@relation = relation
end
def call
@relation.where(status: :pending)
.where("created_at > ?", 24.hours.ago)
.includes(:line_items, :user)
end
end
end
Use for partial page updates without full navigation:
<%# Index page with inline editing %>
<%= turbo_frame_tag "orders" do %>
<% @orders.each do |order| %>
<%= turbo_frame_tag dom_id(order) do %>
<%= render order %>
<% end %>
<% end %>
<% end %>
<%# Edit form that replaces the frame %>
<%= turbo_frame_tag dom_id(@order) do %>
<%= render "form", order: @order %>
<% end %>
Use for real-time updates and multi-element updates:
# Controller action
def create
@order = Order.create(order_params)
respond_to do |format|
format.turbo_stream
format.html { redirect_to orders_path }
end
end
<%# create.turbo_stream.erb %>
<%= turbo_stream.prepend "orders", @order %>
<%= turbo_stream.update "order_count", Order.count %>
Naming convention: controller-name_controller.js
// app/javascript/controllers/dropdown_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["menu"]
static values = { open: Boolean }
toggle() {
this.openValue = !this.openValue
}
openValueChanged() {
this.menuTarget.classList.toggle("hidden", !this.openValue)
}
}
<div data-controller="dropdown" data-dropdown-open-value="false">
<button data-action="click->dropdown#toggle">Menu</button>
<div data-dropdown-target="menu" class="hidden">
<!-- Menu content -->
</div>
</div>
# Edit credentials
bin/rails credentials:edit
# Environment-specific
bin/rails credentials:edit --environment production
Access pattern:
Rails.application.credentials.dig(:aws, :access_key_id)
Rails.application.credentials.stripe[:secret_key]
# config/environments/production.rb
Rails.application.configure do
config.force_ssl = true
config.log_level = :info
config.active_job.queue_adapter = :sidekiq
end
Name by feature, not gem:
# config/initializers/stripe.rb (not payments.rb)
Stripe.api_key = Rails.application.credentials.stripe[:secret_key]
def order_params
params.require(:order).permit(
:shipping_address_id,
:notes,
line_items_attributes: [:id, :product_id, :quantity, :_destroy]
)
end
Avoid callback chains for business logic. Prefer service objects:
# Avoid
class Order < ApplicationRecord
after_create :send_confirmation, :update_inventory, :notify_warehouse
end
# Prefer
class Orders::CreateService
def call
Order.transaction do
order = Order.create!(params)
OrderMailer.confirmation(order).deliver_later
Inventory::DeductService.new(order).call
Warehouse::NotifyJob.perform_later(order.id)
order
end
end
end
Define commonly used queries as scopes:
class Order < ApplicationRecord
scope :recent, -> { where("created_at > ?", 30.days.ago) }
scope :pending, -> { where(status: :pending) }
scope :with_items, -> { includes(:line_items) }
scope :for_user, ->(user) { where(user: user) }
end
For detailed patterns and examples:
references/hotwire-patterns.md - Advanced Turbo and Stimulus patternsreferences/api-conventions.md - API versioning, serialization, authentication patternsnpx claudepluginhub betamatt/claude-plugins --plugin ruby-on-railsGuides Rails code with rubocop-rails-omakase conventions on Turbo Streams, controllers, concerns, services, modern Ruby style, enums, scopes, error handling, and Minitest testing.
Applies 37signals/DHH conventions to Ruby and Rails code: rich domain models, CRUD controllers, concerns, database-backed state, and minimal gems. Covers controllers, models, views (Turbo/Stimulus), architecture, testing (Minitest/fixtures), and code review.
Applies DHH's 37signals Rails style to Ruby code: fat models, thin controllers, Hotwire patterns, REST purity, database constraints, and clarity-over-cleverness. For generation, refactoring, and review.